历史上的今天
今天是:2024年11月08日(星期五)
2021年11月08日 | 51单片机实现在串口接收中断里即时解析数据头的特殊程序框架
2021-11-08 来源:eefocus
一、使用proteus绘制简单的电路图,用于后续仿真

二、编写程序
/********************************************************************************************************************
---- @Project: USART
---- @File: main.c
---- @Edit: ZHQ
---- @Version: V1.0
---- @CreationTime: 20200712
---- @ModifiedTime: 20200712
---- @Description:
---- 波特率是:9600 。
---- 通讯协议:EB GG XX XX XX XX ED
---- 其中第1位EB就是数据头.
---- 其中第2位GG就是数据类型。01代表驱动蜂鸣器,02代表驱动Led灯。
---- 其中第3,4,5,6位XX就是有效数据长度。高位在左,低位在右。
---- 其中第7位ED就是数据尾,在这里也起一部分校验的作用,虽然不是累加和的方式。
---- 在本程序中,
---- 当数据类型是01时,4个有效数据代表一个long类型数据,如果这个数据等于十进制的123456789,那么蜂鸣器就鸣叫一声表示正确。
---- 当数据类型是02时,4个有效数据代表一个long类型数据,如果这个数据等于十进制的123456789,那么LED灯就会闪烁一下表示正确。
---- 十进制的123456789等于十六进制的75bcd15 。
---- 发送以下测试数据,将会分别控制蜂鸣器Led灯。
---- 控制蜂鸣器发送:eb 01 07 5b cd 15 ed
---- 控制LED灯发送:eb 02 07 5b cd 15 ed
---- 单片机:AT89C52
********************************************************************************************************************/
#include "reg52.h"
/*——————宏定义——————*/
#define FOSC 11059200L
#define BAUD 9600
#define T1MS (65536-FOSC/12/500) /*0.5ms timer calculation method in 12Tmode*/
#define const_rc_size 20 /*接收串口中断数据的缓冲区数组大小*/
#define const_receive_time 5 /*如果超过这个时间没有串口数据过来,就认为一串数据已经全部接收完,这个时间根据实际情况来调整大小*/
#define const_voice_short 80 /*蜂鸣器短叫的持续时间*/
#define const_led_short 80 /*LED灯亮的持续时间*/
/*——————变量函数定义及声明——————*/
/*蜂鸣器的驱动IO口*/
sbit BEEP = P2^7;
/*LED*/
sbit LED = P3^5;
unsigned int uiRcregTotal = 0; /*代表当前缓冲区已经接收了多少个数据*/
unsigned char ucRcregBuf[const_rc_size]; /*接收串口中断数据的缓冲区数组*/
/*为串口计时器多增加一个原子锁,作为中断与主函数共享数据的保护*/
unsigned char ucVoiceLock = 0; /*蜂鸣器鸣叫的原子锁*/
unsigned char ucLedLock = 0; /*Led灯点亮时间的原子锁*/
unsigned int uiVoiceCnt = 0; /*蜂鸣器鸣叫的持续时间计数器*/
unsigned int uiRcVoiceTime = 0; /*蜂鸣器发出声音的持续时间*/
unsigned int uiLedCnt = 0; /*Led灯点亮的计时器*/
unsigned long ulBeepData = 0; /*蜂鸣器的数据*/
unsigned long ulLedData = 0; /*LED的数据*/
unsigned char ucUsartStep = 0; /*串口接收字节的步骤变量*/
/**
* @brief 定时器0初始化函数
* @param 无
* @retval 初始化T0
**/
void Init_T0(void)
{
TMOD = 0x01; /*set timer0 as mode1 (16-bit)*/
TL0 = T1MS; /*initial timer0 low byte*/
TH0 = T1MS >> 8; /*initial timer0 high byte*/
}
/**
* @brief 串口初始化函数
* @param 无
* @retval 初始化T0
**/
void Init_USART(void)
{
SCON = 0x50;
TMOD = 0x21;
TH1=TL1=-(FOSC/12/32/BAUD);
}
/**
* @brief 外围初始化函数
* @param 无
* @retval 初始化外围
* 让数码管显示的内容转移到以下几个变量接口上,方便以后编写更上一层的窗口程序。
* 只要更改以下对应变量的内容,就可以显示你想显示的数字。
**/
void Init_Peripheral(void)
{
ET0 = 1;/*允许定时中断*/
TR0 = 1;/*启动定时中断*/
TR1 = 1;
ES = 1; /*允许串口中断*/
EA = 1;/*开总中断*/
}
/**
* @brief 初始化函数
* @param 无
* @retval 初始化单片机
**/
void Init(void)
{
LED = 0;
BEEP = 1;
Init_T0();
Init_USART();
}
/**
* @brief 延时函数
* @param 无
* @retval 无
**/
void Delay_Long(unsigned int uiDelayLong)
{
unsigned int i;
unsigned int j;
for(i=0;i for(j=0;j<500;j++) /*内嵌循环的空指令数量*/ { ; /*一个分号相当于执行一条空语句*/ } } } ///** //* @brief 延时函数 //* @param 无 //* @retval 无 //**/ //void Delay_Short(unsigned int uiDelayShort) //{ // unsigned int i; // for(i=0;i // ; /*一个分号相当于执行一条空语句*/ // } //} /** * @brief Led灯的服务程序 * @param 无 * @retval 无 **/ void led_service(void) { if(uiLedCnt < const_led_short) { LED = 1; /*LED亮*/ } else { LED = 0; } } /** * @brief 定时器0中断函数 * @param 无 * @retval 无 **/ void ISR_T0(void) interrupt 1 { TF0 = 0; /*清除中断标志*/ TR0 = 0; /*关中断*/ /* * 此处多增加一个原子锁,作为中断与主函数共享数据的保护 */ if(ucVoiceLock == 0) /*原子锁判断*/ { if(uiVoiceCnt != 0) { uiVoiceCnt --; BEEP = 0; } else { ; BEEP = 1; } } if(ucLedLock == 0) /*原子锁判断*/ { if(uiLedCnt < const_led_short) { uiLedCnt ++; /*Led灯点亮的时间计时器*/ } } TL0 = T1MS; /*initial timer0 low byte*/ TH0 = T1MS >> 8; /*initial timer0 high byte*/ TR0 = 1; /*开中断*/ } /** * @brief 串口接收数据中断 * @param 无 * @retval 以下是在串口接收中断里即时解析数据头的特殊程序框架, * 它的特点是靠数据头来启动接受有效数据,靠数据尾来识别一串数据接受完毕, * 这里的数据尾也起到一部分的校验作用,让数据更加可靠。这种程序结构适合应用 * 在传输的数据长度不是很长,而且要求响应速度非常高的实时场合。在这种实时要求 * 非常高的场合中,就不像之前一样做数据累加和的复杂运算校验,只用数据尾来做简单的 * 校验确认,目的是尽可能提高处理速度。 **/ void usart_receive(void) interrupt 4 { if(RI == 1) { RI = 0; switch(ucUsartStep) /*串口接收字节的步骤变量*/ { case 0: ucRcregBuf[0] = SBUF; if(ucRcregBuf[0] == 0xeb) /*数据头判断*/ { ucRcregBuf[0] = 0; /*数据头及时清零,为下一串数据的接受判断做准备*/ uiRcregTotal = 1; /*缓存数组的下标初始化*/ ucUsartStep = 1; /*如果数据头正确,则切换到下一步,依次把上位机来的数据存入数组缓冲区*/ } break; case 1: ucRcregBuf[uiRcregTotal] = SBUF; /*依次把上位机来的数据存入数组缓冲区*/ uiRcregTotal ++; if(uiRcregTotal >= 7) /*已经接收了7个字节*/ { if(ucRcregBuf[6] == 0xed) /*数据尾判断,也起到一部分校验的作用,让数据更加可靠,虽然没有用到累加和的检验方法*/ { ucRcregBuf[6] = 0; /*数据尾及时清零,为下一串数据的接受判断做准备*/ switch(ucRcregBuf[1]) /*根据不同的数据类型来做不同的数据处理*/ { case 0x01: /*与蜂鸣器相关*/ ulBeepData = ucRcregBuf[2]; /*把四个字节的数据合并成一个long型的数据*/ ulBeepData = ulBeepData << 8; ulBeepData += ucRcregBuf[3]; ulBeepData = ulBeepData << 8; ulBeepData += ucRcregBuf[4]; ulBeepData = ulBeepData << 8; ulBeepData += ucRcregBuf[5]; if(ulBeepData == 123456789) /*如果此数据等于十进制的123456789,表示数据正确*/ { ucVoiceLock = 1; /*共享数据的原子锁加锁*/ uiVoiceCnt = const_voice_short; /*蜂鸣器发出声音*/ ucVoiceLock = 0; /*共享数据的原子锁解锁*/ } break; case 0x02: /*与Led灯相关*/ ulLedData = ucRcregBuf[2]; /*把四个字节的数据合并成一个long型的数据*/ ulLedData = ulLedData << 8; ulLedData += ucRcregBuf[3]; ulLedData = ulLedData << 8; ulLedData += ucRcregBuf[4]; ulLedData = ulLedData << 8; ulLedData += ucRcregBuf[5]; if(ulLedData == 123456789) /*如果此数据等于十进制的123456789,表示数据正确*/ { ucLedLock = 1; /*共享数据的原子锁加锁*/ uiLedCnt = 0; /*在本程序中,清零计数器就等于自动点亮Led灯*/ ucLedLock = 0; /*共享数据的原子锁解锁*/ } break; } } ucUsartStep = 0; /*返回上一步数据头判断,为下一次的新数据接收做准备*/ } break; } } else { TI = 0; } } /*————————————主函数————————————*/ /** * @brief 主函数 * @param 无 * @retval 实现LED灯闪烁 **/ void main() { /*单片机初始化*/ Init(); /*延时,延时时间一般是0.3秒到2秒之间,等待外围芯片和模块上电稳定*/ Delay_Long(100); /*单片机外围初始化*/ Init_Peripheral(); while(1) { led_service(); /*Led灯的服务程序*/ } } 三、仿真实现
史海拾趣
|
图说微电子最前沿:最好的绝缘介质是什么?-就是什么介质都没有 在集成电路中,将晶体管连接起来的是导线(如图中褐色的是铜线),将导线隔离起来的是绝缘介质(图中绿色部分就是最普遍采用的绝缘介质二氧化硅)。随着集成电路工作频率的提升以及导线之间间距的不断缩小,导线之间寄生电容对电路性能的影响越来 ...… 查看全部问答> |
|
如题,我对硬件不是很了解,我觉得串口转USB,再USB转串口,信号应该没有变化。如果变化了,有没有专业人士解答下这是为什么??? 先谢谢了… 查看全部问答> |
|
最近在做个项目,要用程序修改IP,SUBMASK,GATEWAY的地址,这个程序我作出来了,但是碰到一个问题,当我把静态的改回DHCP动态的时候发生了错误, 提示说是进行了一个非法操作,这是怎么回事呢?我在程序上是这样的一个思路,我先选择是静态的地址还是动态的 ...… 查看全部问答> |
|
尤其是1st of 10 req\'d task args to pass to func ,就是最后输入参数的10个有什么作用,刚看了英语解释,不是很懂,谢谢… 查看全部问答> |
|
如图所示为抗干扰声控开关电路。该电路由话筒S、选频放大器、单稳整形电路IC1、信号存储器IC2a与IC2b、可控硅交流开关SCR及脉冲清零电路IC4等组成。 电路中BG1为9014或3DG4M、3DG201、3DG401、3DG8A和3DG88等。BG2、BG3选用3DG12或3DG130。IC1、I ...… 查看全部问答> |
|
现任TI 应用工程师兼科技委员会高级会员John Betten和现任 TI 高级应用经理兼科技委员会资深成员Robert Kollman 详尽讨论了适用于驱动 LED 和进行 LED 调光的各种开关电源拓扑,并告诉你这些电源的相关优点。与君共享。… 查看全部问答> |





