第41节:在串口接收中断里即时解析数据头的特殊程序框架

发布者:huanli最新更新时间:2016-03-15 来源: eefocus关键字:串口接收  中断  特殊程序框架 手机看文章 扫描二维码
随时随地手机看文章
开场白:

上一节讲了常用的自定义串口通讯协议的程序框架,这种框架在判断一串数据是否接收完毕的时候,都是靠“超过规定的时间内,没有发现串口数据”来判定的,这是我做绝大多数项目的串口程序框架,但是在少数要求实时反应非常快的项目中,这样的程序框架可能会满足不了系统对速度的要求,这一节就是要介绍另外一种响应速度更加快的串口程序框架,要教会大家一个知识点:在串口接收中断里即时解析数据头的特殊程序框架。我在这种程序框架里,会尽量简化数据头和数据尾,同时也简化校验,目的都是为了提高响应速度。

具体内容,请看源代码讲解。

(1)硬件平台:

基于朱兆祺51单片机学习板。

(2)实现功能:

波特率是: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

(3)源代码讲解如下:

#include "REG52.H"

#define const_rc_size 20 //接收串口中断数据的缓冲区数组大小

#define const_receive_time 5 //如果超过这个时间没有串口数据过来,就认为一串数据已经全部接收完,这个时间根据实际情况来调整大小

#define const_voice_short 80 //蜂鸣器短叫的持续时间

#define const_led_short 80 //LED灯亮的持续时间

void initial_myself(void);

void initial_peripheral(void);

void delay_long(unsigned int uiDelaylong);

void T0_time(void); //定时中断函数

void usart_receive(void); //串口接收中断函数

void led_service(void); //Led灯的服务程序。

sbit led_dr=P3^5; //Led的驱动IO口

sbit beep_dr=P2^7; //蜂鸣器的驱动IO口

unsigned int uiRcregTotal=0; //代表当前缓冲区已经接收了多少个数据

unsigned char ucRcregBuf[const_rc_size]; //接收串口中断数据的缓冲区数组

unsigned int uiVoiceCnt=0; //蜂鸣器鸣叫的持续时间计数器

unsigned char ucVoiceLock=0; //蜂鸣器鸣叫的原子锁

unsigned int uiRcVoiceTime=0; //蜂鸣器发出声音的持续时间

unsigned int uiLedCnt=0; //Led灯点亮的计时器

unsigned char ucLedLock=0; //Led灯点亮时间的原子锁

unsigned long ulBeepData=0; //蜂鸣器的数据

unsigned long ulLedData=0; //LED的数据

unsigned char ucUsartStep=0; //串口接收字节的步骤变量

void main()

{

initial_myself();

delay_long(100);

initial_peripheral();

while(1)

{

led_service(); //Led灯的服务程序

}

}

void led_service(void)

{

if(uiLedCnt

{

led_dr=1; //开Led灯

}

else

{

led_dr=0; //关Led灯

}

}

void T0_time(void) interrupt 1 //定时中断

{

TF0=0; //清除中断标志

TR0=0; //关中断

/* 注释一:

* 此处多增加一个原子锁,作为中断与主函数共享数据的保护,实际上是借鉴了"红金龙吸味"关于原子锁的建议.

*/

if(ucVoiceLock==0) //原子锁判断

{

if(uiVoiceCnt!=0)

{

uiVoiceCnt--; //每次进入定时中断都自减1,直到等于零为止。才停止鸣叫

beep_dr=0; //蜂鸣器是PNP三极管控制,低电平就开始鸣叫。

}

else

{

; //此处多加一个空指令,想维持跟if括号语句的数量对称,都是两条指令。不加也可以。

beep_dr=1; //蜂鸣器是PNP三极管控制,高电平就停止鸣叫。

}

}

if(ucLedLock==0) //原子锁判断

{

if(uiLedCnt

{

uiLedCnt++; //Led灯点亮的时间计时器

}

}

TH0=0xfe; //重装初始值(65535-500)=65035=0xfe0b

TL0=0x0b;

TR0=1; //开中断

}

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=ulBeepData+ucRcregBuf[3];

ulBeepData=ulBeepData<<8;

ulBeepData=ulBeepData+ucRcregBuf[4];

ulBeepData=ulBeepData<<8;

ulBeepData=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=ulLedData+ucRcregBuf[3];

ulLedData=ulLedData<<8;

ulLedData=ulLedData+ucRcregBuf[4];

ulLedData=ulLedData<<8;

ulLedData=ulLedData+ucRcregBuf[5];

if(ulLedData==123456789) //如果此数据等于十进制的123456789,表示数据正确

{

ucLedLock=1; //共享数据的原子锁加锁

uiLedCnt=0; //在本程序中,清零计数器就等于自动点亮Led灯

ucLedLock=0; //共享数据的原子锁解锁

}

break;

}

}

ucUsartStep=0; //返回上一步数据头判断,为下一次的新数据接收做准备

}

break;

}

}

else //我在其它单片机上都不用else这段代码的,可能在51单片机上多增加" TI = 0;"稳定性会更好吧。

{

TI = 0;

}

}

void delay_long(unsigned int uiDelayLong)

{

unsigned int i;

unsigned int j;

for(i=0;i

{

for(j=0;j<500;j++) //内嵌循环的空指令数量

{

; //一个分号相当于执行一条空语句

}

}

}

void initial_myself(void) //第一区 初始化单片机

{

led_dr=0; //关Led灯

beep_dr=1; //用PNP三极管控制蜂鸣器,输出高电平时不叫。

//配置定时器

TMOD=0x01; //设置定时器0为工作方式1

TH0=0xfe; //重装初始值(65535-500)=65035=0xfe0b

TL0=0x0b;

//配置串口

SCON=0x50;

TMOD=0X21;

TH1=TL1=-(11059200L/12/32/9600); //这段配置代码具体是什么意思,我也不太清楚,反正是跟串口波特率有关。

TR1=1;

}

void initial_peripheral(void) //第二区 初始化外围

{

EA=1; //开总中断

ES=1; //允许串口中断

ET0=1; //允许定时中断

TR0=1; //启动定时中断

}

复制代码总结陈词:

前面花了4节内容仔细讲了各种串口接收数据的常用框架,从下一节开始,我开始讲串口发送数据的程序框架,这种程序框架是什么样的?欲知详情,请听下回分解-----通过串口用delay延时方式发送一串数据。

关键字:串口接收  中断  特殊程序框架 引用地址:第41节:在串口接收中断里即时解析数据头的特殊程序框架

上一篇:第40节:常用的自定义串口通讯协议
下一篇:第42节:通过串口用delay延时方式发送一串数据

推荐阅读最新更新时间:2024-03-16 14:47

MSP430-中断事件介绍
MSP430在没有事件发生时进入低功耗模式,事件发生时,通过中断唤醒CPU,事件处理完毕后,CPU再次进入低功耗状态。由于CPU的运算速度和退出低功耗的速度很快,所以在应用中,CPU大部分时间都处于低功耗状态。 MSP430的中断分为3种:系统复位、不可屏蔽中断、可屏蔽中断。 (1)系统复位的中断向量为0xFFFE。 (2)不可屏蔽中断的中断向量为0xFFFC。响应不可屏蔽中断时,硬件自动将OFIE、NMIE、ACCVIE复位。软件首先判断中断源并复位中断标志,接着执行用户代码。退出中断之前需要置位OFIE、NMIE、ACCVIE,以便能够再次响应中断。需要特别注意点:置位OFIE、NMIE、 ACCVIE后,必须立即退出
[单片机]
Cortex-M3内核的异常中断
有许多朋友在学习,或者开发 STM32 时都遇到过HardFault_Handler的情况。 那么,又有多少人认真去分析过Fault这类异常中断呢? 下面结合STM32F1(Cortex‐M3内核)来给大家讲述一下这些异常中断的内容。 1Cortex‐M3异常 说起Fault,我们就要说一下Cortex‐M3的异常。 Cortex‐M3 在内核上搭载了一个异常响应系统, 支持为数众多的系统异常和外部中断。 CM3部分异常列表: 这些异常中断的优先级,有些却是固定的,有些是可以通过软件来配置,如UART发送中断、DMA中断等。 相信大家看到这个列表不会陌生,因为在STM32的启动代码,中断代码中都会看到这些异常。 比如在st
[单片机]
Cortex-M3内核的异常<font color='red'>中断</font>
C51单片机的中断体系结构
80C51的中断系统有5个中断源(8052有 6个) ,2个优先级,可实现二级中断嵌套 。MCS-51系列单片机中断系统的机构如下: 与中断系统相关的特殊寄存器: 1)中断允许控制寄存器(IE)------ 控制各中断的开放和屏蔽 2)中断优先级控制寄存器(IP)------设置各中断的优先级 3)定时器/计数器控制寄存器(TCON)----定时器和外部中断的控制 4)串行口控制寄存器(SCON)------串行中断的控制 中断类型分为三类: 1)T0、T1是2个定时器/计数器中断,由片内定时器提供; 2)INT0、INT1是2个外部中断,由引脚P3.2和P3.2提供; 3)RX、TX为串行口中断所用,由片内串口提供。
[单片机]
基于TMS320F2812集中供电系统的串口通信设计
引言 集中供电系统是电量的自动计量及管理的发展趋势,它将促进电力系统的潜能得到最大限度的发挥。 本集中供电系统利用RS-485通信,网络应用计算机、通信技术等,以DSP为核心、将智能计量与通信控制单元有机结合起来。 TMS320F2812串行通信接口概述 TMS320F2812串行通信接口(SCI)是一个双线通信异步串行通信接口,为减少串口通信时CPU的开销,F2812的串口支持16级接收和发送FIFO。串行通信接口支持与CPU以及其他使用费归零格式的异步外设之间的异步串行数字通信,它的接收器和发送器都是双级缓冲器,有各自独立的控制位与中断位,都可以同时工作在全双工模式下,为保证数据的完整性,串行通信接口对接收的数据进行间
[工业控制]
51单片机中断号对应的中断
interrupt()interrupt n{} n 是表示中断对应的是中断号 外部中断0(INT0),对应中断号是0, 中断入口地址0003H 定时/计数器0(T1),对应中断号1 ,中断入口地址000BH 外部中断1(INT1),中断号2 入口地址0013H 定时/计数器1(T1)中断号3 入口地址001BH 串行口中(RI/TI)中断号4 入口地址0023H 这五个是AT89S51的,52还多了下面这个 定时/计数器2(T2)中断号5,入口地址002BH
[单片机]
中断系统的应用举例 (含源程序)
使用外部中断0,当每次响应中断时,P1口依次输出高电 平,使8个发光二极管依次循环熄灭闪烁。 1) 电路设计 ORG 0000H LJMP MAIN ;转主程序 ORG 0003H ;外部中断0入口地址 LJMP EXTER ;转中断程序 ORG 1000H MAIN: SETB IT0 ;外部中断0下降沿有效 SETB EX0 ;外部中断0允许 SETB EA ;总中断允许 LOOP: AJMP LOOP ;等待中断 ORG 1050H ;中断程序入口 EXTER: MOV R2, #0FFH ;置循环次数 MOV A, #01H ;灯亮初值FLASH: RR A ;右移一位 MOV R7, #0FFH
[单片机]
<font color='red'>中断</font>系统的应用举例 (含源<font color='red'>程序</font>)
J-Link + ADS + mini2440调试中断问题
在RAM中在线调试,一般什么跑马灯啊,蜂鸣器的程序都可以。今天调一个中断的程序就不行。 就是一个简单的外部中断,通过按键获取外部中断,可是中断一直进不去(通过设置断点,按键按了也不能跳进去)。找了网上的一些资料看,说要设置中断向量? “因为调试过程中没有开中断,开中断则要正确设置异常向量。”这句话小弟有点不太理解。 下面我把代码贴上来,大伙帮我看看,感谢致敬! #include def.h //所要包含的头文件 #include option.h #include 2440addr.h #include 2440lib.h #include 2440slib.h //*****
[单片机]
GPIO做输出还能作外部中断输入吗?
偶尔会有人问起STM32芯片的GPIO做输出时还是否可能作为外部中断触发输入,这里一起聊聊该话题。 作为STM32芯片,其外部中断触发源可以是硬件模式或软件模式。所谓软件模式就是通过操作相关寄存器产生内部中断触发信号并向内核NVIC控制器申请中断。硬件模式自然是指来自GPIO引脚的电平跳变信号经边沿检测器形成中断触发信号向内核申请中断。【注:还有个别外设事件也可以作为外部中断触发源映射到外部中断控制器。】 我们这里要谈的是基于硬件模式的外部中断话题。当STM32的GPIO作为输出时,可能是通用GPIO输出也可能是基于其它外设复用情况下的输出,即复用输出。 下图是GPIO作为基本输入输出时的功能框图。 下面是GPIO作为
[单片机]
GPIO做输出还能作外部<font color='red'>中断</font>输入吗?
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved