飞道的博客

第十一届蓝桥杯单片机国赛试题----------极为容易上手的模块编程思想

247人阅读  评论(0)

在码字之前,我们按照常理先上题目。









我个人觉得,在做到这套程序题的时候,我们先不要急着想着每个模块怎么去做,我们需要花上一两分钟左右的时间将大致内容浏览一下。接着重点主要看题目中的模块硬件框图,根据模块硬件框图,确定自己需要用到哪些模块,然后在新建的代码文件框架构建好。这部分内容,我在之前的电子钟的分析中讲过,如何搭建整体模块,然后框架中细化内容。
这里我们分析完所需的模块后,进入眼帘的是数码管的显示。我借阅过大多数蓝桥杯单片机比赛者的代码,自己总结了一套针对蓝桥杯数码管显示的处理方法—数组。那就是将数码管显示,数据处理,其他模块功能独立化开来,避免脚踩西瓜皮,走到哪写到哪。
接下里,我就以这套国赛为例,仔细分析。
1.数码管显示:
数码管实际上只需要显示四种不同的界面,前三种不好归为一类,后三种都关于参数界面的显示,而且显示上几乎一模一样。
所以初始定义数组的时候我们可以更具数码管显示图,大致定义如下:
code uchar smg_duan[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xc6,0x86,0x8c,0xff};//数码管段选
uchar tab_1[]={0,0,10,0,0,10,0,0}; //数据界面1图
uchar tab_2[]={11,14,14,14,14,0,0,0};//数据界面2图
uchar tab_3[]={12,14,0,0,0,14,14,0}; //数据界面3图
uchar tab_4[]={13,0,14,14,14,14,0,0};//参数界面界图
2.数据处理(依据不同的情况进行):
void Data_process() //数据处理
{
if(guang>20) g_flag=0;
else g_flag=1;
tab_1[0]=rtc_time[0]/10;
tab_1[1]=rtc_time[0]%10;
tab_1[3]=rtc_time[1]/10;
tab_1[4]=rtc_time[1]%10;
tab_1[6]=rtc_time[2]/10;
tab_1[7]=rtc_time[2]%10;
tab_2[5]=wendu/100;
tab_2[6]=wendu/100/10;
tab_2[7]=wendu%10;
tab_3[2]=guang/100;
tab_3[3]=guang/100/10;
tab_3[4]=guang%10;
tab_3[7]=g_flag;
if(parameter_face0) { tab_4[1]=1;tab_4[6]=t_c/10;tab_4[7]=t_c%10;}
if(parameter_face
1) { tab_4[1]=2;tab_4[6]=w_c/10;tab_4[7]=w_c%10;}
if(parameter_face==2) { tab_4[1]=3;tab_4[6]=14;tab_4[7]=d_c;}
}
大家不需要在意这些未知的定义变量,大家的目光是需要看我对对应的数组的处理。我这种用数组确定数码管显示,处理数据的方法,是独立开来的,编写完后,可以直接放在定时中断中。
这里大致概括思路:数码管显示+数据处理+LED数据处理+外设+键盘扫描
接下来直接上代码:
为了便于需要的人下载,完整的代码我会再以资源的形式上传。
Main.c

#include <STC15F2K60S2.H>
#include "ds1302.h"
#include "iic.h"
#include "onewire.h"
#define uchar unsigned char
#define uint  unsigned int
#define Latch(x,y)  {P0=y;P2=(P2&0x1f)|(x<<4);P2&=0x1f;}
#define  key_state0  0 //检测按键是否按下;
#define  key_state1  1  //检测是否抖动;
#define  key_state2  2 //检测按键是否松开
code uchar smg_duan[]={
   0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xc6,0x86,0x8c,0xff};//数码管段选
uchar rtc_time[]={
   16,59,50};
uchar tab_1[]={
   0,0,10,0,0,10,0,0};
uchar tab_2[]={
   11,14,14,14,14,0,0,0};
uchar tab_3[]={
   12,14,0,0,0,14,14,0};
uchar tab_4[]={
   13,0,14,14,14,14,0,0};
uchar inter_face=0; //界面
uchar data_face=0;   //数据界面
uchar parameter_face=0;//参数界面
uchar t_c=17; //时间参数
uchar w_c=25; //温度参数
uchar d_c=4;//灯参数
uint wendu; //温度存放值
uint guang; //光强存放值
uchar g_flag; //光强标志
uchar Ucled=0;//led灯
uchar fg_1;  //暗三秒标志
uchar fg_2;  //亮三秒标志
void System_init()  //系统初始化
{
   
  Latch(10,0);
	Latch(14,0xff);
}
void Timer0Init(void)		//1毫秒@12.000MHz
{
   
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	EA=1;
	ET0=1;
}

uchar Key_scan() //矩阵键盘,状态机切换扫描
{
   
  uchar key_value;
	static char key_state=0;
  uchar key_return=0 ;
	uchar key_1,key_2;
	P44=1;P42=1;P3=0xf0;
	if(P44==0) key_1=0x70;
	if(P42==0) key_1=0xb0;
	if(P35==0) key_1=0xd0;
	if(P34==0) key_1=0xe0;
	if((P44==1)&&(P42==1)&&(P35==1)&&(P34==1)) key_1=0xf0;
  P44=0;P42=0;P3=0x0f;
  if(P30==0) key_2=0x0e;
	if(P31==0) key_2=0x0d;
	if(P32==0) key_2=0x0b;
	if(P33==0) key_2=0x07;
	if((P3&0x0f)==0x0f) key_2=0x0f;
	key_value=key_1|key_2;
	switch(key_state)
	{
   
	  case key_state0 : if(key_value!=0xff) key_state=key_state1;
		break;
		case key_state1:
			 if(key_value!=0xff)
			 {
   
			   if(key_value==0x77) key_return=4;
					  if(key_value==0x7b) key_return=5;
							 if(key_value==0xb7) key_return=8;
						     if(key_value==0xbb) key_return=9;
							key_state=key_state2;
					}
			  else key_state=key_state0;
					break;
		case key_state2:
			 if(key_value==0xff) key_state=key_state0;
		            break;
			 }
	    return key_return;
	}
void Data_process() //数据处理
{
   
	if(guang>20) g_flag=0;
	else g_flag=1;
  tab_1[0]=rtc_time[0]/10;
	tab_1[1]=rtc_time[0]%10;
	tab_1[3]=rtc_time[1]/10;
	tab_1[4]=rtc_time[1]%10;
  tab_1[6]=rtc_time[2]/10;
	tab_1[7]=rtc_time[2]%10;
  tab_2[5]=wendu/100;
	tab_2[6]=wendu/100/10;
  tab_2[7]=wendu%10;
  tab_3[2]=guang/100;
	tab_3[3]=guang/100/10;
  tab_3[4]=guang%10;
	tab_3[7]=g_flag;
	if(parameter_face==0) {
    tab_4[1]=1;tab_4[6]=t_c/10;tab_4[7]=t_c%10;}
	if(parameter_face==1) {
    tab_4[1]=2;tab_4[6]=w_c/10;tab_4[7]=w_c%10;}
	if(parameter_face==2) {
    tab_4[1]=3;tab_4[6]=14;tab_4[7]=d_c;}
 }
void Smg_display()  //数码管显示函数
{
   
	static uchar discom;
	static uchar xiao;
  Latch(14,0xff);
  Latch(12,1<<discom);
  if(inter_face==0&&data_face==0) {
    Latch(14,smg_duan[tab_1[discom]]);}
	if(inter_face==0&&data_face==1) {
    if(discom==6) xiao=0x7f;else xiao=0xff; Latch(14,smg_duan[tab_2[discom]]&xiao);}
	if(inter_face==0&&data_face==2) {
   if(discom==2) xiao=0x7f;else xiao=0xff;Latch(14,smg_duan[tab_3[discom]]&xiao);}
	if(inter_face==1) {
   Latch(14,smg_duan[tab_4[discom]]);}
	if(++discom==8) discom=0;
}
void Key_process(uchar key_value)
{
    
	 static uchar m=0;
	 static uchar n=0;
	 static uchar k=0;
  switch(key_value)
	{
   	case 4:  if(m==0) {
   inter_face=1;m=1;parameter_face=0;} else {
   inter_face=0;m=0;data_face=0;}break;
    case 5:  if(inter_face==0) {
   if(++n==3){
   n=0;} if(n==0) data_face=0;if(n==1) data_face=1;if(n==2) data_face=2; }
             if(inter_face==1) {
   if(++k==3){
   k=0;} if(k==0) parameter_face=0;if(k==1) parameter_face=1;if(k==2) parameter_face=2;}
            break;
		case 8: if(inter_face==1) {
    
		                            switch(parameter_face)
			                          {
   
		case 0:     if(t_c==0)t_c=0; else t_c--;break;
		case 1:     if(w_c==0) w_c=0; else w_c--;break;
    case 2:     if(d_c==4) d_c=4;  else d_c--;break;																	
													
																} 
		                           }		break;
    case 9:		if(inter_face==1) {
    
		                            switch(parameter_face)
			                          {
   
		case 0:     if(t_c==23)t_c=23; else t_c++;break;
		case 1:     if(w_c==99) w_c=99; else w_c++;break;
    case 2:     if(d_c==8) d_c=8;  else d_c++;break;													
																} 			              
		                           }	 break;	

}
	}

	
void Led_control() //led灯控制模块
{
   
  if(rtc_time[0]>=t_c&&(0<(rtc_time[0]-8))) Ucled&=0xfe;
	                              else Ucled|=0x01;	
	if(wendu>w_c*10) Ucled|=0x02;
	                 else Ucled&=0xfd;
  if(g_flag==1&&fg_1==1)  {
   Ucled&=0xfb;fg_1=0;}
	if(g_flag==0&&fg_2==1)  {
    Ucled|=0x04;fg_2=0;}
	                   
	Ucled|=0xf8;
 if(g_flag==1) {
   Ucled&=~(1<<(d_c-1));}
//	                 else Ucled|=~(1<<(d_c-1));
}


void main() 
{
   
System_init();
Timer0Init();
	RTC_write(rtc_time);
	while(1)
	{
    Key_process(Key_scan() );
	 RTC_read(rtc_time);
		wendu=rd_temperature();
}



}
void Time0()  interrupt 1
{
   
 static uchar i=0;
 static uchar j=0;
 static uint k1=0;
	static uint k2=0;
	Data_process();
	Smg_display();
	Led_control();
 if(g_flag==1) if(++k1==3000) {
   k1=0; fg_1=1;}
 if(g_flag==0) if(++k2==3000) {
   k2=0; fg_2=1;}
 if(++i==100) {
     guang=Pcf_convert();i=0;}
 if(++j==10) {
    Latch(8,Ucled);j=0;}


}

IIC

/*
  程序说明: IIC总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台 8051,12MHz
  日    期: 2011-8-9
*/

#include "reg52.h"
#include "intrins.h"
#include "iic.h"

#define DELAY_TIME 5

#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1

//总线引脚定义
sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */

void IIC_Delay(unsigned char i)
{
   
    do{
   _nop_();}
    while(i--);        
}
//总线启动条件
void IIC_Start(void)
{
   
    SDA = 1;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 0;
    IIC_Delay(DELAY_TIME);
    SCL = 0;	
}

//总线停止条件
void IIC_Stop(void)
{
   
    SDA = 0;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//发送应答
void IIC_SendAck(bit ackbit)
{
   
    SCL = 0;
    SDA = ackbit;  					// 0:应答,1:非应答
    IIC_Delay(DELAY_TIME);
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SCL = 0; 
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//等待应答
bit IIC_WaitAck(void)
{
   
    bit ackbit;
	
    SCL  = 1;
    IIC_Delay(DELAY_TIME);
    ackbit = SDA;
    SCL = 0;
    IIC_Delay(DELAY_TIME);
    return ackbit;
}

//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
   
    unsigned char i;

    for(i=0; i<8; i++)
    {
   
        SCL  = 0;
        IIC_Delay(DELAY_TIME);
        if(byt & 0x80) SDA  = 1;
        else SDA  = 0;
        IIC_Delay(DELAY_TIME);
        SCL = 1;
        byt <<= 1;
        IIC_Delay(DELAY_TIME);
    }
    SCL  = 0;  
}

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
   
    unsigned char i, da;
    for(i=0; i<8; i++)
    {
      
    	SCL = 1;
	IIC_Delay(DELAY_TIME);
	da <<= 1;
	if(SDA) da |= 1;
	SCL = 0;
	IIC_Delay(DELAY_TIME);
    }
    return da;    
}
unsigned int Pcf_convert() //光明电阻转化
{
   
	unsigned int light;
  IIC_Start();
	IIC_SendByte(0x90); 
	IIC_WaitAck();
	IIC_SendByte(0x41);
	IIC_WaitAck();
	IIC_Start();
	IIC_SendByte(0x91);
	IIC_WaitAck();
	light=IIC_RecByte()*100/51;
  IIC_SendAck(1);
  IIC_Stop();  
 return light;
}

onewire.h

/*
  程序说明: 单总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台(外部晶振12MHz) STC89C52RC单片机
  日    期: 2011-8-9
*/
#include "reg52.h"
#include "onewire.h"

sbit DQ = P1^4;  //单总线接口

//单总线延时函数
void Delay_OneWire(unsigned int t)  //STC89C52RC
{
    
	unsigned char j;
	while(t--)
	{
    for(j=10;j>0;j--);}
}

//通过单总线向DS18B20写一个字节
void Write_DS18B20(unsigned char dat)
{
   
	unsigned char i;
	for(i=0;i<8;i++)
	{
   
		DQ = 0;
		DQ = dat&0x01;
		Delay_OneWire(5);
		DQ = 1;
		dat >>= 1;
	}
	Delay_OneWire(5);
}

//从DS18B20读取一个字节
unsigned char Read_DS18B20(void)
{
   
	unsigned char i;
	unsigned char dat;
  
	for(i=0;i<8;i++)
	{
   
		DQ = 0;
		dat >>= 1;
		DQ = 1;
		if(DQ)
		{
   
			dat |= 0x80;
		}	    
		Delay_OneWire(5);
	}
	return dat;
}

//DS18B20设备初始化
bit init_ds18b20(void)
{
   
  	bit initflag = 0;
  	
  	DQ = 1;
  	Delay_OneWire(12);
  	DQ = 0;
  	Delay_OneWire(80);
  	DQ = 1;
  	Delay_OneWire(10); 
    initflag = DQ;     
  	Delay_OneWire(5);
  
  	return initflag;
}
unsigned int rd_temperature(void)
{
   
	unsigned char temp_h,temp_l;
	unsigned int temp;
  init_ds18b20();
  Write_DS18B20(0xcc);
  Write_DS18B20(0x44);
  Delay_OneWire(10);
 init_ds18b20();
 Write_DS18B20(0xcc);
 Write_DS18B20(0xbe);
	temp_l= Read_DS18B20();
	temp_h=Read_DS18B20();
	temp=temp_h;
	temp<<=8;
	temp|=temp_l;
	temp=temp*10*0.0625+0.5;
	return temp;
}

ds1302.h

/*
  程序说明: DS1302驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台 8051,12MHz
  日    期: 2011-8-9
*/

#include <reg52.h>
#include <intrins.h>
#include "ds1302.h"

sbit SCK=P1^7;		
sbit SDA=P2^3;		
sbit RST = P1^3;   // DS1302复位												

void Write_Ds1302(unsigned  char temp) 
{
   
	unsigned char i;
	for (i=0;i<8;i++)     	
	{
    
		SCK=0;
		SDA=temp&0x01;
		temp>>=1; 
		SCK=1;
	}
}   

void Write_Ds1302_Byte( unsigned char address,unsigned char dat )     
{
   
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1; 	_nop_();  
 	Write_Ds1302(address);	
 	Write_Ds1302(dat);		
 	RST=0; 
}

unsigned char Read_Ds1302_Byte ( unsigned char address )
{
   
 	unsigned char i,temp=0x00;
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1;	_nop_();
 	Write_Ds1302(address);
 	for (i=0;i<8;i++) 	
 	{
   		
		SCK=0;
		temp>>=1;	
 		if(SDA)
 		temp|=0x80;	
 		SCK=1;
	} 
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
	SCK=1;	_nop_();
	SDA=0;	_nop_();
	SDA=1;	_nop_();
	return (temp);			
}
/*****DS1302时钟芯片部分*****/
void RTC_write(unsigned char *rtc_put) 
{
   
	unsigned char temp;
 Write_Ds1302_Byte( 0x8e,0x00 );
 temp=rtc_put[0]/10*16+rtc_put[0]%10;
 Write_Ds1302_Byte( 0x84,temp );
	 temp=rtc_put[1]/10*16+rtc_put[1]%10;
 Write_Ds1302_Byte( 0x82,temp );
	 temp=rtc_put[2]/10*16+rtc_put[2]%10;
 Write_Ds1302_Byte( 0x80,temp );
 Write_Ds1302_Byte( 0x8e,0x80 );

}
void RTC_read(unsigned char *rtc_put)
{
   
  unsigned char temp;
temp=Read_Ds1302_Byte( 0x85 );
rtc_put[0]=temp/16*10+temp%16;
temp=Read_Ds1302_Byte( 0x83 );
rtc_put[1]=temp/16*10+temp%16;
temp=Read_Ds1302_Byte( 0x81 );
rtc_put[2]=temp/16*10+temp%16;

}

转载:https://blog.csdn.net/a12345abcdd/article/details/115679447
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场