单片机接口资源配置: 系统功能需求: 系统配置和自检功能: 数据接收和按键计时功能: 数据发送功能: 校验和生成和检测功能: 附录:帧定义 校验和的计算:除去帧头和帧尾后将帧中的其他数据求和并取低8位; 按键允许命令帧: 时钟数据搜索命令帧: 时钟数据返回帧: 帧结构头文件frame.h(内容如下) #define FRAME_HEAD 0xAA //帧头 set.h ** 接口配置:略 串口状态机:
从机上电后进行初始化,通过读取P2口进行从机地址配置;
发光二极管以每秒一次的频率闪烁(亮0.5秒,灭0.5秒);
检测到一次按键按下操作后,熄灭发光二极管。
从机接收主机程序(PC机上的串口调试程序)的按键允许命令帧并进行校验;
校验正确并且目的地址是广播地址或者本从机的地址,通过发光二极管长亮指示,并允许按键操作;
按键按下后,尽可能准确记录按键的动作时点(定时器的低8位、定时器的高8位、50ms值、秒、分、小时);
按键操作只能响应一次,重复按键操作不响应;
按键的动作时点记录后,发光二极管以每秒一次的频率闪烁(亮0.5秒,灭0.5秒)。
从机接收主机程序发来的时钟数据搜索命令帧并进行校验;
如果校验正确并且数据帧的目的地址是本从机的地址,从机将前面记录的按键动作时点数据(定时器的低8位、定时器的高8位、50ms值、秒、分、小时)按附录中的时钟数据返回帧的帧格式回传给主机;
时钟数据返回帧回传结束后,熄灭发光二极管。
发送数据帧时能自动生成数据帧校验和;
每帧数据在发送帧尾前,发送一字节的当前帧数据的校验和;
接收数据帧时能检测校验和并判断接收数据是否正确。
帧长:不计帧头、帧尾和校验和字节。
帧头 帧长 目的地址 源地址 命令字 校验和 帧尾
AA 04 FF F0 01 F4 66
帧头 帧长 目的地址 源地址 命令字 保留字 校验和 帧尾
AA 05 01 F0 03 00 F9 66
帧头 帧长 目的地址 源地址 命令字 TL0 TH0 50ms 秒 分 时 校验和 帧尾
AA 0A F0 01 07 01 B6 09 03 00 00 C5 66
//帧格式定义#define FRAME_FOOT 0x66 //帧尾 #define FRAME_LEN 0x00 //帧长 #define FRAME_DST_ADR 0x01 //目的地址 #define FRAME_SRC_ADR 0x02 //源地址 #define FRAME_CMD 0x03 //命令字 #define FRAME_DATA 0x04 //帧数据起始 //帧命令定义 #define READY 0x01 //按键允许命令 #define TIME_SERCH 0x03 //时钟数据轮询命令 #define TIME_BACK 0x07 //时钟数据返回命令 //地址定义 #define BROAD_ADR 0xFF //广播地址 #define MASTER_ADR 0xF0 //主机地址
原理图如下
#include<reg52.h> #include<set.h> unsigned char time_h = 0,time_m = 0,time_s = 0,time_ms = 0,vis_p36 = 1; unsigned char send[11]={0xaa,0x0a,0xf0}; sbit p36 = P3^6; sbit p37 = P3^7; unsigned char js_data[20],len = 0,vis_key = 0,key_down = 0,init_key = 0; unsigned char data_from_sbuf = 0,stare = 0,head = 0,js_t = 0; void interrupt_T0() interrupt 1{//定时器T0中断 没过50毫秒进入中断 TH0 = 0x4b; TL0 = 0xfc; //因为50000/1.085 = 46083 65535-46083=19452=0x4bfc TH0=0x4b TL0=0xfc time_ms += 1;//50毫秒计数加一 time_s += time_ms / 20;//若50毫秒计数加到20 也就是过去里1秒 秒数加一 time_m += time_s / 60;//秒数加到60 分钟数加一 time_h += time_m / 60;//分钟数加到60 小时数加一 time_ms %= 20;//数加到20复位0 time_s %= 60;//秒数加到60复位 time_m %= 60;// time_h %=24;// if(vis_p36 && time_ms == 10)p36 = 1;// if(vis_p36 && time_ms == 0)p36 = 0;//当VIS_p36为1时 LED灯就会闪烁 if(head == 1){//这段代码意思是:当接收到帧头后 在0.5秒之内没有接收到帧尾 那么0.5秒之后就将状态机复位 就是发生了数据丢失 js_t ++; if(js_t == 10){ js_t = 0;head = 0; stare = 0; } } } void interrupt_EX0()interrupt 0{//外部中断0 P32口下降沿触发中断 EX0 = 0;//当发生中断后关闭外部中断0 vis_p36 = 0;//将LED闪烁标志位置0 init_key = 1;//初始化标志位 第一次按下后就表示初始化完成 可以开始接受数据了 if(vis_key == 1){//当接收到允许按键命令后 vis_key=1 之后按下按键就会将数据记录到数组中去 send[3] = Local_address;//记录源地址 就是本机地址(P2口的数据) send[4] = TIME_BACK; send[5] = TL0; send[6] = TH0; send[7] = time_ms; send[8] = time_s; send[9] = time_m; send[10] = time_h; vis_p36 = 1;//按下按键后LED灯闪烁 key_down = 1;//接收到按键命令后 按键按下标志位 } } /* 发送数据 */ void send_data(){ unsigned char i,k = 0; if(key_down == 0 || vis_key == 0)return;//表示就收到时钟数据返回命令 但是还没有接收到按键允许命令或者接收到了按键允许命令但按键还没有按下 那么就退出 p37 = 1;//将收发控制位置1表示发送数据 ES = 0;//关闭串口中断 就是发送的时候不在接收数据 TI = 0;//TI位置0 当有一条写SBUF操作就启动发送 for(i = 0;i < 11;i++){//循环发送 //p37 = 1; if(i)k += send[i];//计算校验和 不计算帧头 因为i=0不执行该语句 SBUF = send[i];//写SBUF操作 while(TI==0);//查询TI位 因为发送完成后硬件对对TI置1 TI = 0;//置0开始发送下一个数据 } SBUF = k;//发送校验和 while(TI==0); TI = 0; SBUF = FRAME_FOOT;//发送帧尾 while(TI==0); TI = 0; ES = 1;//开启串口中断 可以接收数据了 p37 = 0;//接收控制位 p36 = 0;//数据发送后熄灭Led vis_p36 = 0;//LED闪烁标志位置0 vis_key = 0;//将按键允许清0 key_down = 0;//按键按下清0 } void data_handle1(){ unsigned char i = 0,k = 0; P1 = ~P1; if(js_data[3] == 0x01){//按键允许命令 for(i = 0;i < 4;i++)k += js_data[i];//计算校验和 if(k != js_data[4])return;//校验和错误 退出 //下面是校验正确后的操作 p36 = 1;//LED长亮 EX0 = 1;//开启外部中断 就是按下按键后就会进入中断 vis_key = 1;//把按键允许开启 就是按下按键后就会记录数据了 } if(js_data[4] == 0x03){//时钟数据返回命令 for(i = 0;i < 5;i++)k += js_data[i];//计算校验和 if(k != js_data[5])return;//校验和错误 退出 TI = 0; send_data();//去发送数据 } } void data_headle2(){//状态机函数 //此函数不做解释 请看图理解 switch(stare){ case 0x00:{ if(data_from_sbuf == FRAME_HEAD){ stare = 0x01; head = 1; }else stare = 0x00; break; } case 0x01:{ if(data_from_sbuf == 0x04){ stare = 0x02; js_data[0] = 0x04; }else if(data_from_sbuf == 0x05){ stare = 0x06; js_data[0] = 0x05; }else stare = 0x00; break; } case 0x02:{ if(data_from_sbuf == BROAD_ADR || data_from_sbuf == Local_address){ stare = 0x03; js_data[1] = data_from_sbuf; }else stare = 0x00; break; } case 0x03:{ if(data_from_sbuf == MASTER_ADR){ stare = 0x04; js_data[2] = MASTER_ADR; }else stare = 0x00; break; } case 0x04:{ if(data_from_sbuf == 0x01){ stare = 0x0a; js_data[3] = 0x01; len = 4; }else stare = 0x00; break; } case 0x0a:{ js_data[len] = data_from_sbuf; stare = 0x0b; break; } case 0x0b:{ if(data_from_sbuf == FRAME_FOOT){ head = 0; js_t = 0; data_handle1(); } stare = 0x00; break; } case 0x06:{ if(data_from_sbuf == Local_address){ stare = 0x07; js_data[1] = Local_address; }else stare = 0x00; break; } case 0x07:{ if(data_from_sbuf == MASTER_ADR){ stare = 0x08; js_data[2] = MASTER_ADR; }else stare = 0x00; break; } case 0x08:{ if(data_from_sbuf == 0x03){ stare = 0x09; js_data[3] = 0x03; }else stare = 0x00; break; } case 0x09:{ js_data[4] = data_from_sbuf; stare = 0x0a; len = 5; break; } default:{ stare = 0x00; } } } void funins()interrupt 4 { data_from_sbuf = SBUF;//将接收到的数据送给data_from_sbuf data_headle2();//进入状态机 判断当前状态和进入下一个状态 RI = 0;//因为接受到数据后硬件会对RI位置1 清0准备接收下一个数据 } void init(){//初始化函数 p36 = 0; EA = 1;//开启总总段 ET0 = 1;//允许定时器T0中断 TMOD = 0x21; //T0:16位定时模式 T1:8位自动重装模式 TH0 = 0x4b; TL0 = 0xfc;//因为50000/1.085 = 46083 65535-46083=19452=0x4bfc TH0=0x4b TL0=0xfc TR0 = 1;//开启定时器T0 EX0 = 1;//允许外部中断0 IT0 = 1;//开启外部中断0 //设置定时器T1 //波特率 = 2^SMON * 11.0592M /32*12*(256 - T0初) T0 = 253=0xfd; TH1 = TL1 = 0xfd; TR1 = 1;//开启T1 ES = 1;//允许串口中断 SM0 = 0; SM1 = 1;//工作于方式一 8位异步通信 RI = 0; SM2 = 1; REN = 1;//允许接收数据 p37 = 0; } void main(){ init(); while(init_key == 0); p36 = 0; while(1){ } }
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算