历史上的今天
返回首页

历史上的今天

今天是: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灯的服务程序*/

}

}

 

三、仿真实现


推荐阅读

史海拾趣

Compound Photonics公司的发展小趣事

经过几年的努力,Compound Photonics在LCoS领域取得了显著的进步,成为了业内知名的LCoS方案商之一。公司的技术与产品得到了市场的广泛认可,成功应用在Lumus最新的二维扩瞳模组中。这次合作不仅提升了Compound Photonics的市场地位,也为其带来了可观的商业回报。

Carlisle Interconnect Technologies公司的发展小趣事

Carlisle Interconnect Technologies(当时名为Tensolite)的创业之路始于1940年,在纽约Tarrytown的一个小工厂里。公司创始人凭借对微型绝缘电线和电缆的深刻理解和前瞻视野,开创了绝缘电线电缆的新纪元。Tensolite这个名称,象征着产品的高拉伸强度和紧凑轻巧的特性,这种创新的设计理念很快在市场上赢得了口碑。公司的第一根绝缘线产品成功应用于电加热,为第二次世界大战期间的空军飞行员提供了温暖的手套和飞行服,这一成就不仅彰显了公司的技术实力,也为后续发展奠定了坚实的基础。

常忆科技(CHINGIS)公司的发展小趣事

常忆科技股份有限公司,始创于1995年,总部位于台湾。在电子行业的发展历程中,常忆科技以其专注于IC设备制造领域的执着和创新能力,逐渐崭露头角。公司成立之初,便致力于开发P型晶体管非挥发性内存,由pFlash和pFusion两个事业单位组成,分别负责不同方面的工作。pFlash专注于开发和生产标准型NOR内存,而pFusion则负责向晶圆代工厂及IC设计公司提供嵌入式非挥发内存的生产技术及知识产权,并提供定制化设计及技术咨询服务。

随着消费电子产品、电脑及周边设备、无线通讯和网络装置等领域的快速发展,常忆科技的产品得到了广泛应用。公司凭借其卓越的技术和产品质量,逐渐在市场上占据了一席之地,为后续的蓬勃发展奠定了坚实基础。

Endicott Research Group Inc (ERG)公司的发展小趣事

随着医疗、工业和军事市场对电源设备的需求不断增长,ERG凭借其深厚的技术积累和创新能力,逐渐在这些领域获得了广泛的认可。他们的产品以其高性能和稳定性赢得了众多客户的信赖。特别是在医疗设备领域,ERG的电源产品为诊断和治疗设备提供了可靠的动力支持,为医疗行业的发展做出了重要贡献。

HM International公司的发展小趣事

进入21世纪,随着LED技术的快速发展,ERG看到了固态照明市场的巨大潜力。2008年,公司决定成立一个新的部门——ERG Lighting,专注于为固态照明市场设计、制造和分销LED驱动器和其他照明配件。这一举措极大地拓展了公司的业务范围,并使其在市场上占据了有利地位。ERG Lighting的成立,不仅为公司带来了新的增长点,还进一步巩固了其在电源转换产品领域的领先地位。

广东奥科公司的发展小趣事

广东奥科公司深知品质是企业生存和发展的关键。因此,公司始终将品质管理放在首位,从原材料采购到生产流程控制,再到产品出厂检验,每一个环节都严格把控品质。同时,公司还建立了完善的品质管理体系和持续改进机制,通过不断优化生产工艺和提升产品质量,确保每一款产品都能满足客户的期望和需求。

问答坊 | AI 解惑

摄像机部件中英文对照

本帖最后由 jameswangsynnex 于 2015-3-3 19:59 编辑 是呀 希望大家能够多多完善 …

查看全部问答>

图说微电子最前沿:最好的绝缘介质是什么?-就是什么介质都没有

在集成电路中,将晶体管连接起来的是导线(如图中褐色的是铜线),将导线隔离起来的是绝缘介质(图中绿色部分就是最普遍采用的绝缘介质二氧化硅)。随着集成电路工作频率的提升以及导线之间间距的不断缩小,导线之间寄生电容对电路性能的影响越来 ...…

查看全部问答>

连接调试问题

   VS2005连接目标机(wince5.0),目标机需要运行相应的程序,才能连接上,这些程序是在开发机上哪得到的?…

查看全部问答>

CDMA模块哪种比较好呢?价格低一些

老板准备买个CDMA Modem,用来发短信…

查看全部问答>

串口转USB,再USB转串口。信号变了吗?

   如题,我对硬件不是很了解,我觉得串口转USB,再USB转串口,信号应该没有变化。如果变化了,有没有专业人士解答下这是为什么???   先谢谢了…

查看全部问答>

修改DHCP的程序的问题

最近在做个项目,要用程序修改IP,SUBMASK,GATEWAY的地址,这个程序我作出来了,但是碰到一个问题,当我把静态的改回DHCP动态的时候发生了错误, 提示说是进行了一个非法操作,这是怎么回事呢?我在程序上是这样的一个思路,我先选择是静态的地址还是动态的 ...…

查看全部问答>

有没有作过取交流同步信号的朋友

本人现在需要做一个LED控制方案,需要采样交流信号做同步处理,不知道有没有哪位朋友能够提供具体的思路…

查看全部问答>

taskSpawn( )的详解

尤其是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 ...…

查看全部问答>

LED 照明的电源拓扑结构

现任TI 应用工程师兼科技委员会高级会员John Betten和现任 TI 高级应用经理兼科技委员会资深成员Robert Kollman 详尽讨论了适用于驱动 LED 和进行 LED 调光的各种开关电源拓扑,并告诉你这些电源的相关优点。与君共享。…

查看全部问答>