赞
踩
目的:利用PROTUES仿真软件、串口调试助手、虚拟串口,搭建单片机与PC通信仿真平台,熟悉单片机串口的配置及与PC机的通信方法;尝试制定通信协议(含开始码、指令、数据、停止码),单片机根据通信协议解析接收到的内容,并根据接收的指令执行相应的操作。
程序功能:1.时分秒的动态显示。2.用三个按键实现时分秒的修改,调节的数字闪烁提示。
3.串口控制时钟的暂停、开始、清零、读取、设置时间
串口协议格式:s+指令+数据+e
s:表示开始码
指令:
p:计时暂停(无数据位)
r:计时重启(无数据位)
c:显示清零(无数据位)
q:查询当前时间(无数据位)
t:设置时间(数据位格式为6位数字)
- /*******************************************************************************
- 程序功能:1.时分秒的动态显示。2.用三个按键实现时分秒的修改,调节的数字闪烁提示。
- 3.串口控制时钟的暂停、开始、清零、读取、设置时间
- 串口协议格式:s+指令+数据+e
- s:表示开始码
- 指令:
- | p:计时暂停(无数据位) |
- | r:计时重启(无数据位) |
- | c:显示清零(无数据位) |
- | q:查询当前时间(无数据位)
- | t:设置时间(数据位格式为6位数字)
- *******************************************************************************/
-
- #include <reg52.h> //包含需要的头文件
-
- #define u8 unsigned char
- #define u16 unsigned int
-
- u8 WeiMa[6]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF};
- u8 DuanMa[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
-
- //函数声明
- void Delay_ms(u16 xms);
- void ShuMaGuan(u8 wei,u8 duan);
- void Display_Timer(u8 hour,u8 min,u8 sec);
- u8 Key_Scan();
- void PutChar(u8 n);
- void UartInit();
- void PutString(u8 *p);
- void Key_Timer_Set();
- void Uart_Timer_Set();
- void Pintf_Uart();
-
-
- //引脚定义
- sbit SW1=P3^2;
- sbit SW2=P3^3;
- sbit SW3=P3^4;
-
- u8 Hour=0,Min=0,Sec=0;//全局变量,时分秒
- u8 mode=0;//全局变量:状态切换,0:时钟显示,1:调节时;2:调节分;3:调节秒
- bit flash_tip=1;//数码管闪烁标志,为0时数码管熄灭,为一时数码管显示
-
- #define Data_SIZE 15 //数据长度
- u8 USART_RX_BUF[Data_SIZE]; //接收缓冲,最大Data_SIZE个字节.末字节为换行符
- u8 Start_Receiving=0; //开始接收标志位
- u8 Receive_OK=0; //接收完毕接收位 1为接收完毕
-
- //函数功能:定时器初始化
- void Time0init()
- {
- TMOD|=0x01; //设置定时器模式
- TF0=0; //清除TF0标志
- TH0=(65536-50000)/256; //设置定时初值
- TL0=(65536-50000)%256; //设置定时初值
- TR0=1; //定时器0允许计时
- ET0=1; //中断允许
- EA=1; //CPU中断允许位打开
- }
-
- //串口初始化
- void UartInit() //9600bps@11.0592MHz
- {
-
- PCON &= 0x8F; //波特率倍速
- SCON = 0x50; //8位数据,可变波特率
- TMOD &= 0x0F; //清除定时器1模式位
- TMOD |= 0x20; //设定定时器1为8位自动重装方式
- TL1 = 0xFD; //设定定时初值
- TH1 = 0xFD; //设定定时器重装值
- TR1 = 1; //启动定时器1
- EA=1;
- ES=1; //打开接收中断
- }
-
- /*******************************************************************************
- * 函 数 名: void main()
- * 函数功能: 主函数
- *******************************************************************************/
- void main()
- {
-
-
- Time0init();//定时器
- UartInit(); //串口
- Pintf_Uart();//输入提示
- while(1)
- {
- Key_Timer_Set();//按键控制时钟
- Uart_Timer_Set();//按键调节时钟
- Display_Timer(Hour,Min,Sec);//数码管显示
-
- }
- }
-
- /*******************************************************************************
- * 函 数 名: void Pintf_Uart()
- * 函数功能: 串口助手输入指示
- *******************************************************************************/
- void Pintf_Uart()
- {
- /***************输入指示*******************/
- PutString("Please input:s+command(data)+e\r\n");
- PutString("Stop_Time:spe\r\n");
- PutString("Start_Time:sre\r\n");
- PutString("Zero_Time:sce\r\n");
- PutString("Read_Time:sqe\r\n");
- PutString("Set_Time:st******e\r\n");
- /*******************************************/
- }
-
- /*******************************************************************************
- * 函 数 名: void Key_Timer_Set()
- * 函数功能: //按键调节时钟
- *******************************************************************************/
- void Key_Timer_Set()
- {
- u8 keynum;
- keynum=Key_Scan();//按键返回值
- if(keynum) //非0表示有按键按下
- {
- switch(keynum) //判断是哪个按键按下,按键一调节模式,按键2自加,按键3自减
- {
- case 1:if(++mode>=4) mode=0;break; //++mode为先自增再判断是否大于4
- case 2:
- if(mode==1) if(++Hour>=24) Hour=0;//++mode为先自增再判断是否大于4
- if(mode==2) if(++Min>=60) Min=0;//++Min先自增再判断是否大于60
- if(mode==3) if(++Sec>=60) Sec=0;//++Sec先自增再判断是否大于60
- break;
- case 3:
- if(mode==1) if(--Hour==255) Hour=23;//--Hour先自增再判断是否溢出
- if(mode==2) if(--Min==255) Min=59;//--Min先自增再判断是否大溢出
- if(mode==3) if(--Sec==255) Sec=59;//--Sec先自增再判断是否大溢出
- break;
- default:break;
- }
- }
- }
- /*******************************************************************************
- * 函 数 名: void Key_Timer_Set()
- * 函数功能: 串口调节时钟
- 串口协议格式:s+指令+数据+e
- s:表示开始码
- 指令:
- | p:计时暂停(无数据位) |
- | r:计时重启(无数据位) |
- | c:显示清零(无数据位) |
- | q:查询当前时间(无数据位)
- | t:设置时间(数据位格式为6位数字)
- *******************************************************************************/
- void Uart_Timer_Set()
- {
- static u8 Hour_1,Min_1,Sec_1;//时间暂存
- if(Receive_OK) //如果串口接收到数据
- {
- Receive_OK=0;
- switch(USART_RX_BUF[0])//存入数组的数据没有开始码,所以第一个数据是指令
- {
- case 'p': //时钟暂停
- if(USART_RX_BUF[1]!='e')//说明第2位数组的数据不是停止码
- PutString("Error!\r\n");
- else
- {
- TR0=0;
- PutString("Stop OK!\r\n");
- }
-
- break;
- case 'r': //开始计时
- if(USART_RX_BUF[1]!='e')//说明第2位数组的数据不是停止码
- PutString("Error!\r\n");
- else
- {
- TR0=1;
- PutString("Start OK!\r\n");
- }
- break;
- case 'c': //清零
- if(USART_RX_BUF[1]!='e')//说明第2位数组的数据不是停止码
- PutString("Error!\r\n");
- else
- {
- Hour=0;
- Min=0;
- Sec=0;
- PutString("Zero OK!\r\n");
- }
-
- break;
- case 'q': //查询当前时间
- if(USART_RX_BUF[1]!='e')//说明第2位数组的数据不是停止码
- PutString("Error!\r\n");
- else
- {
- PutString("The time is:");
- PutChar(Hour/10+48); //转化ASCII码字符,0为48,1为48+1=49.....
- PutChar(Hour%10+48);
- PutChar(':');
- PutChar(Min/10+48);
- PutChar(Min%10+48);
- PutChar(':');
- PutChar(Sec/10+48);
- PutChar(Sec%10+48);
- PutString("\r\n");
- }
-
- break;
- case 't': //设置时间
- if(USART_RX_BUF[7]!='e')//如果接收到的数据不是6位数字,说明第7位数组的数据不是停止码
- PutString("Error!\r\n");
- else
- {
- Hour_1=(USART_RX_BUF[1]-48)*10+(USART_RX_BUF[2]-48); //转化成十进制
- Min_1=(USART_RX_BUF[3]-48)*10+(USART_RX_BUF[4]-48); //转化成十进制
- Sec_1=(USART_RX_BUF[5]-48)*10+(USART_RX_BUF[6]-48); //转化成十进制
- if(Hour_1>23 || Min_1>59 || Sec_1>59) //超出时间阈值
- PutString("Error!\r\n");
- else
- {
- Hour=Hour_1;
- Min=Min_1;
- Sec=Sec_1;
- PutString("Set OK!\r\n");
- }
- }
- break;
- default:PutString("Error!\r\n");break;
- }
- ES=1; //开启接收
- }
- }
-
- /*******************************************************************************
- * 函 数 名: void Delay_ms(u16 xms)
- * 函数功能: 软件延时函数,xms为延时多少毫秒
- *******************************************************************************/
- void Delay_ms(u16 xms)
- {
-
- unsigned char i, j;
- while(xms--)
- {
- i = 2;
- j = 135;
- do
- {
- while (--j);
- } while (--i);
- }
- }
-
- /*******************************************************************************
- * 函 数 名: void ShuMaGuan(u8 wei,u8 duan)
- * 函数功能: 静态显示一位,参数:wei控制位选duan控制段选,表示要显示的一个数字
- *******************************************************************************/
- void ShuMaGuan(u8 wei,u8 duan)
- {
- P1=WeiMa[wei]; //位选
- P2=DuanMa[duan]; //段选
- Delay_ms(1); //间隔一段时间扫描
- P1=0xFF;
- P2=0xFF; //消隐
- }
-
- /*******************************************************************************
- * 函 数 名: void Display_Timer(u8 hour,u8 min,u8 sec)
- * 函数功能:数码管动态显示
- flash_tip为数码管闪烁标志,为0时数码管熄灭,为一时数码管显示
- flash_tip每4.5秒进行取反
- *******************************************************************************/
- void Display_Timer(u8 hour,u8 min,u8 sec)
- {
- if(mode!=1 || flash_tip==1) //mode=1时,左边的条件一直为假,当flash_tip=1时,或运算为真,进入if,数码管显示
- {
- ShuMaGuan(5,hour/10);
- ShuMaGuan(4,hour%10);
- }
- else P1=0xFF;
-
-
- if(mode!=2 || flash_tip==1)//mode=2时,左边的条件一直为假,当flash_tip=1时,或运算为真,进入if,数码管显示
- {
- ShuMaGuan(3,min/10);
- ShuMaGuan(2,min%10);
- }
- else P1=0xFF;
-
-
- if(mode!=3 || flash_tip==1)//mode=3时,左边的条件一直为假,当flash_tip=1时,或运算为真,进入if,数码管显示
- {
- ShuMaGuan(1,sec/10);
- ShuMaGuan(0,sec%10);
- }
- else P1=0xFF;
- }
-
- /*******************************************************************************
- * 函 数 名: u8 Key_Scan()
- * 函数功能: 独立按键检测,按键按下分别返回1.2.3
- *******************************************************************************/
- u8 Key_Scan()
- {
- static u8 key_up=1; //按键按松开标志
- if(key_up && (SW1==0 || SW2==0 || SW3==0))
- {
- Delay_ms(10); //去抖动
- key_up=0; //松手标志为0,那么下次再检测,if结果为0,则不会进入这里的语句
- if(SW1==0) return 1;
- if(SW2==0) return 2;
- if(SW3==0) return 3;
- }
- else if(SW1 == 1 && SW2 == 1 && SW3 == 1) key_up=1; //松手标志
- return 0; // 无按键按下
- }
-
- /*******************************************************************************
- * 函 数 名: void PutChar(u8 n)
- * 函数功能: 发送一个字符
- *******************************************************************************/
- void PutChar(u8 n)
- {
- SBUF=n;
- while(!TI);
- TI=0;
- }
-
- /*******************************************************************************
- * 函 数 名: void PutString(u8 *p)
- * 函数功能: 发送字符串
- *******************************************************************************/
- void PutString(u8 *p)
- {
- while(*p!='\0')
- {
- PutChar(*p);
- p++;
- }
- }
- /*******************************************************************************
- * 函 数 名: void uart() interrupt 4
- * 函数功能: 串口中断服务函数,单片机接收数据并存入USART_RX_BUF[]数组中
- 开始码s不存入数组
- *******************************************************************************/
- void uart() interrupt 4
- {
- static u8 Data_count=0;
- u8 Data;
- if(RI==1)
- {
- RI=0;
- Data=SBUF;
- if(Data=='s')
- {
- Start_Receiving=1; //开始接收数据
- }
- else if(Start_Receiving)
- {
- USART_RX_BUF[Data_count++]=Data;//数据还没结束发送,就存到USART_RX_BUF[]数组中
- if(Data=='e')
- {
- Start_Receiving=0;
- Data_count=0;
- Receive_OK=1;
- ES=0;
- }
-
- }
-
- }
- }
-
- /*******************************************************************************
- * 函 数 名: void Time0() interrupt 1
- * 函数功能: 定时器0中断服务函数,时钟效果
- *******************************************************************************/
- void Time0() interrupt 1
- {
- static unsigned char flag_1,flag_2;
- TH0=(65536-50000)/256;
- TL0=(65536-50000)%256;//重新赋初值
-
- if(mode==0)flag_1++; //mode为0时,数码管正常显示
- else flag_2++;
-
- if(flag_1==20 && mode==0) //每秒执行一次
- {
- flag_1=0;
- if(++Sec>=60) //++Sec先自增再判断是否大于60
- {
- Sec=0;
- if(++Min>=60)//++Min先自增再判断是否大于60
- {
- Min=0;
- if(++Hour>=24)//++Hour先自增再判断是否大于60
- {
- Hour=0;
- }
- }
- }
- }
- if(flag_2==9)
- {
- flash_tip=~flash_tip;//每4.5秒进行取反
- flag_2=0;
- }
-
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。