单片机串口通信的发送与接收
stm32f103,串口收发的原理

STM32F103的串口收发原理基于串行通信协议。
串行通信是一种数据传输方式,数据在两个设备之间逐位传输。
在STM32F103中,串口(USART)模块用于实现串行通信。
串口收发的原理可以分为以下几个步骤:
1.初始化串口:在开始串行通信之前,需要配置串口的参数,如波特率、数据位、停止位、校验位
等。
这些参数可以根据需要进行设置,以匹配通信设备的规格和协议要求。
2.发送数据:当需要发送数据时,STM32F103会将数据写入串口的发送缓冲区。
然后,串口模
块会自动将数据一位一位地发送出去。
发送数据的顺序是从低位到高位依次发送。
3.接收数据:接收数据的过程与发送数据相反。
当接收到数据时,串口模块会将数据一位一位地读
取,并存储在接收缓冲区中。
然后,STM32F103可以从接收缓冲区中读取数据。
同样地,接收数据的
顺序也是从低位到高位依次读取。
4.错误检测与处理:为了确保数据的正确传输,可以在通信过程中加入校验和(checksum)或奇
偶校验(parity)等错误检测机制。
在接收数据时,接收方可以计算校验和或奇偶校验,并与发送方的数
据进行比较。
如果发现错误,可以请求重新发送数据。
需要注意的是,具体的串口配置和操作可能会根据不同的STM32系列和型号有所不同。
因此,在实际应用中,建议参考相关文档和参考手册,以了解特定型号的STM32的串口配置和操作方法。
单片机串口通信原理

单片机串口通信原理
单片机串口通信原理是指通过串口进行数据的发送和接收。
串口通信是一种异步通信方式,它使用两根信号线(TXD和RXD)进行数据的传输。
在发送数据时,单片机将待发送的数据通过串口发送数据线(TXD)发送出去。
发送的数据会经过一个串口发送缓冲区,然后按照一定的通信协议进行处理,并通过串口传输线将数据发送给外部设备。
在接收数据时,外部设备将待发送的数据通过串口传输线发送给单片机。
单片机接收数据线(RXD)会将接收到的数据传
输到一个串口接收缓冲区中。
然后,单片机会根据通信协议进行数据的解析和处理,最后将数据保存在内部的寄存器中供程序使用。
串口通信协议通常包括数据位、停止位、校验位等信息。
数据位指的是每个数据字节占据的位数,常见的有8位和9位两种。
停止位用于表示数据的结束,常用的有1位和2位两种。
校验位用于检测数据在传输过程中是否发生错误,常见的校验方式有奇偶校验和无校验。
总的来说,单片机串口通信原理是通过串口发送数据线和接收数据线进行数据的传输和接收,并通过一定的通信协议进行数据的解析和处理。
这种通信方式可以实现单片机与外部设备的数据交换,广泛应用于各种嵌入式系统和物联网设备中。
单片机串口收发时序

单片机串口收发时序引言单片机串口通信是一种常用的通信方式。
在这种通信方式中,通过发送和接收串口数据,可以实现单片机与外部设备之间的数据传输。
而正确的串口收发时序是保证通信正常进行的关键。
串口通信原理串口通信是通过发送和接收电平变化来传输数据的。
一般使用的是异步串口通信方式,其中包括发送端和接收端,发送端将数据进行序列化,并通过串口线发送给接收端,接收端将接收到的数据进行反序列化,得到原始数据。
串口收发时序串口收发时序是指在通信过程中各个时钟信号的变化情况。
下面详细介绍串口收发时序的每个步骤。
时钟信号串口通信中最重要的时钟信号是波特率,即每秒钟发送的比特数。
波特率决定了串口数据传输的速度。
一般常用的波特率有9600、115200等。
发送端时序发送端的时序可以分为以下几个步骤: 1. 准备数据:发送端首先要准备要发送的数据。
2. 数据序列化:发送端将准备好的数据进行序列化,转换成电平变化的串口信号。
3. 起始位:发送端在数据序列前加上一个起始位,用来标识数据的开始。
4. 数据位:发送端按照波特率将数据位一个一个发送出去。
5. 奇偶校验位:发送端可以选择是否加入奇偶校验位,用来检测数据是否传输出错。
6. 停止位:发送端在数据序列后加上一个或多个停止位,用来标识数据的结束。
7. 等待确认:发送端在发送完一个字节的数据后,等待接收端的确认信号,确保数据已经正确接收。
接收端时序接收端的时序可以分为以下几个步骤: 1. 等待起始位:接收端在接收数据前,等待起始位的到来,用来标识数据的开始。
2. 数据位:接收端按照波特率开始接收数据位。
3. 奇偶校验位:如果发送端加入了奇偶校验位,接收端会检测数据是否传输出错。
4. 停止位:接收端在接收完所有数据位后,等待停止位的到来,用来标识数据的结束。
5. 确认信号:接收端在接收完一个字节的数据后,发送确认信号给发送端,表示数据已经正确接收。
时序示意图下图是串口收发时序的示意图:发送端:起始位数据位奇偶校验位停止位低电平高低变化高低变化高电平------ ------- -------- ------接收端:起始位数据位奇偶校验位停止位确认信号低电平高低变化高低变化高电平高电平串口收发时序的注意事项在进行串口通信时,需要注意以下几点: 1. 波特率要设置一致:发送端和接收端的波特率要设置成相同的值,才能保证数据传输的准确性。
单片机串口通信协议

单片机串口通信协议1. 引言单片机串口通信是一种常见的数据通信方式,它允许单片机与其他外部设备进行通信。
串口通信协议定义了数据传输的格式、波特率等参数,确保通信的稳定和可靠性。
本文将介绍单片机串口通信协议的基本原理和常用协议。
2. 串口通信基础串口通信是通过串行数据传输来实现的。
其中,UART(通用异步收发传输器)是实现串口通信的重要组件。
UART将并行数据转换为串行数据,并通过串口进行传输。
在单片机中,常用的串口通信引脚是TX(发送)和RX(接收)。
3. 串口通信协议串口通信协议定义了数据传输时各个数据包的格式和规则。
常见的串口通信协议有以下几种:3.1. RS-232RS-232是最早出现的串口通信协议之一。
它定义了数据传输的电气特性和信号级别。
RS-232使用9个引脚进行数据传输,包括发送和接收数据线、数据控制线等。
该协议具有较长的最大传输距离和可靠性,但通信速率相对较慢。
3.2. RS-485RS-485是一种多点通信的串口协议。
相比于RS-232,RS-485支持多个设备之间的通信。
它使用不同的信号级别和电气特性,可实现更远的传输距离和更高的通信速率。
RS-485通信中设备分为主设备和从设备,主设备负责控制通信流程。
3.3. SPISPI(Serial Peripheral Interface)是一种同步串口通信协议,常用于单片机与外部设备之间的通信。
SPI使用四条引脚进行通信,包括时钟线、数据线、主设备输出从设备输入线和主设备输入从设备输出线。
SPI通信速率较快,适用于高速数据传输。
3.4. I2CI2C(Inter-Integrated Circuit)是一种多主从通信的串口协议。
I2C使用两条引脚进行通信,包括时钟线和数据线。
在I2C总线上,可以连接多个设备,实现多个设备之间的通信和数据交换。
I2C通信速率较慢,但具有较简单的硬件设计和较低的功耗。
4. 协议选择和配置选择合适的串口通信协议需要考虑通信距离、通信速率、设备数量等因素。
单片机中的串口通信技术

单片机中的串口通信技术串口通信技术是指通过串行接口将数据传输和接收的技术。
在单片机领域,串口通信是一种常见的数据交互方式。
本文将介绍单片机中的串口通信技术,并探讨其在实际应用中的重要性。
一、串口通信的原理串口通信是指通过串行接口传输数据的方式,其中包括一个数据引脚和一个时钟引脚。
数据引脚用于传输二进制数据,在每个时钟周期内,数据引脚上的数据会被读取或写入。
时钟引脚则用于控制数据的传输速度。
单片机中的串口通信主要包含两个部分:发送和接收。
发送时,单片机将数据转换为二进制形式,并通过串口发送出去。
接收时,单片机会从串口接收到二进制数据,并将其转换为可识别的格式。
通过发送和接收两个过程,单片机可以与外部设备进行数据交互。
二、串口通信的类型在单片机中,串口通信主要包含两种类型:同步串口和异步串口。
同步串口是指发送和接收两个设备之间使用相同的时钟信号,以保持数据同步。
同步串口通信速度快,但需要额外的时钟信号输入。
异步串口则是通过发送数据前提供起始位和终止位来区分不同数据帧的方式进行通信。
异步串口通信的优势是不需要额外的时钟信号,但速度相对较慢。
在实际应用中,通常使用异步串口通信。
异步串口通信相对简单易用,适合多种应用场景。
三、单片机串口通信的实现单片机中实现串口通信通常需要以下几个方面的内容:1. 串口通信引脚配置:单片机需要连接到一个串口芯片或者其他外部设备,因此需要配置相应的引脚作为串口通信的数据引脚和时钟引脚。
2. 波特率设置:波特率是指单位时间内传输的数据位数。
在进行串口通信时,发送端和接收端的波特率需要相同。
单片机中通常通过寄存器设置波特率,以确保数据传输的稳定性。
3. 数据发送和接收:在单片机中,通过将数据写入发送缓冲器并启动发送操作来发送数据。
接收数据时,单片机会接收到串口中的数据,并将其保存在接收缓冲器中。
4. 中断机制:在进行串口通信时,单片机通常会使用中断机制来处理数据接收和发送。
中断机制可以减轻单片机的负担,提高系统效率。
51单片机串口通信(相关例程)

51单片机串口通信(相关例程) 51单片机串口通信(相关例程)一、简介51单片机是一种常用的微控制器,它具有体积小、功耗低、易于编程等特点,被广泛应用于各种电子设备和嵌入式系统中。
串口通信是51单片机的常见应用之一,通过串口通信,可以使单片机与其他外部设备进行数据交互和通信。
本文将介绍51单片机串口通信的相关例程,并提供一些实用的编程代码。
二、串口通信基础知识1. 串口通信原理串口通信是通过串行数据传输的方式,在数据传输过程中,将信息分为一个个字节进行传输。
在51单片机中,常用的串口通信标准包括RS232、RS485等。
其中,RS232是一种常用的串口标准,具有常见的DB-9或DB-25连接器。
2. 串口通信参数在进行串口通信时,需要设置一些参数,如波特率、数据位、停止位和校验位等。
波特率表示在单位时间内传输的比特数,常见的波特率有9600、115200等。
数据位表示每个数据字节中的位数,一般为8位。
停止位表示停止数据传输的时间,常用的停止位有1位和2位。
校验位用于数据传输的错误检测和纠正。
三、串口通信例程介绍下面是几个常见的51单片机串口通信的例程,提供给读者参考和学习:1. 串口发送数据```C#include <reg51.h>void UART_Init(){TMOD = 0x20; // 设置计数器1为工作方式2(8位自动重装) TH1 = 0xFD; // 设置波特率为9600SCON = 0x50; // 设置串口工作方式1,允许串行接收TR1 = 1; // 启动计数器1}void UART_SendChar(unsigned char dat){SBUF = dat; // 发送数据while (!TI); // 等待发送完成TI = 0; // 清除发送完成标志}void main(){UART_Init(); // 初始化串口while (1){UART_SendChar('A'); // 发送字母A}}```2. 串口接收数据```C#include <reg51.h>void UART_Init(){TMOD = 0x20; // 设置计数器1为工作方式2(8位自动重装) TH1 = 0xFD; // 设置波特率为9600SCON = 0x50; // 设置串口工作方式1,允许串行接收TR1 = 1; // 启动计数器1}void UART_Recv(){unsigned char dat;if (RI) // 检测是否接收到数据{dat = SBUF; // 读取接收到的数据 RI = 0; // 清除接收中断标志// 处理接收到的数据}}void main(){UART_Init(); // 初始化串口EA = 1; // 允许中断ES = 1; // 允许串口中断while (1)// 主循环处理其他任务}}```3. 串口发送字符串```C#include <reg51.h>void UART_Init(){TMOD = 0x20; // 设置计数器1为工作方式2(8位自动重装) TH1 = 0xFD; // 设置波特率为9600SCON = 0x50; // 设置串口工作方式1,允许串行接收TR1 = 1; // 启动计数器1}void UART_SendString(unsigned char *str){while (*str != '\0')SBUF = *str; // 逐个发送字符while (!TI); // 等待发送完成TI = 0; // 清除发送完成标志str++; // 指针指向下一个字符}}void main(){UART_Init(); // 初始化串口while (1){UART_SendString("Hello, World!"); // 发送字符串}}```四、总结本文介绍了51单片机串口通信的基础知识和相关编程例程,包括串口发送数据、串口接收数据和串口发送字符串。
单片机指令的串口通信实现方法

单片机指令的串口通信实现方法串口通信是指通过串行通信接口实现的数据传输方式。
在单片机系统中,串口通信是一种重要的通信方式,可以实现与外部设备(如PC 机、传感器等)的数据交互。
本文将介绍单片机指令的串口通信实现方法,包括硬件连接和软件编程两方面。
一、硬件连接串口通信需要通过发送器和接收器两个设备来完成数据的发送和接收。
在单片机系统中,可使用通用异步收发器(UART)作为串行通信接口。
下面是串口通信的硬件连接步骤:1. 将单片机与UART连接:首先,确保单片机具有UART接口,并根据其引脚定义将UART的发送线(TXD)连接到单片机的接收引脚,接收线(RXD)连接到单片机的发送引脚。
2. 选择波特率:波特率指每秒钟传送的位数,通常使用的波特率有9600、115200等。
在发送和接收数据时,单片机和外部设备需要使用相同的波特率,以保证数据的正确传输。
3. 连接外部设备:根据实际需求,将UART的发送线和接收线分别连接到外部设备的接收引脚和发送引脚。
二、软件编程实现单片机指令的串口通信需要编写相应的软件程序。
下面是基于C语言的软件编程实现方法:1. 初始化串口:在程序开始时,需要对串口进行初始化设置。
通过设置寄存器来配置波特率、数据位、停止位等参数。
2. 发送数据:使用发送指令将待发送的数据写入UART的数据寄存器,等待数据传输完成。
3. 接收数据:通过接收指令读取UART接收到的数据,并进行相应的处理。
可以使用中断或轮询方式进行数据接收。
4. 错误处理:在数据传输过程中,可能会出现错误,例如帧错误、奇偶校验错误等。
需要进行相应的错误处理操作,例如重新发送数据或发出错误提示。
5. 通信协议:根据通信需求,可以制定相应的通信协议。
通信协议包括数据帧结构、数据格式、数据校验等内容,用于确保数据的可靠传输。
三、实例演示下面通过一个简单的示例来演示单片机指令的串口通信实现方法。
假设我们需要实现从单片机向PC机发送一条消息,并接收PC机返回的确认信息。
单片机教程_-串口通信

单片机教程_-串口通信单片机教程串口通信在单片机的世界里,串口通信是一项至关重要的技术。
它就像是单片机与外部世界交流的“语言”,让单片机能够与其他设备进行有效的数据传输和信息交换。
无论是在工业控制、智能家居,还是在各种电子设备中,串口通信都扮演着不可或缺的角色。
接下来,让我们一起深入了解单片机中的串口通信。
首先,我们来认识一下什么是串口通信。
简单来说,串口通信是一种逐位传输数据的通信方式。
它将数据一位一位地按照顺序进行发送和接收,就像一个人在依次说出一个个的字。
与并行通信不同,并行通信是同时传输多位数据,而串口通信虽然速度相对较慢,但它的线路简单,成本较低,因此在很多应用场景中被广泛使用。
在单片机中,实现串口通信通常需要几个关键的部分。
首先是串口控制器,它负责控制数据的发送和接收。
就像是一个交通指挥员,指挥着数据的流向。
然后是串口引脚,通过这些引脚,数据得以进出单片机。
串口通信有其特定的参数设置,这包括波特率、数据位、停止位和校验位。
波特率决定了数据传输的速度,就像汽车行驶的速度一样。
常见的波特率有 9600、115200 等。
数据位则规定了每次传输的数据位数,一般有 8 位、7 位等。
停止位表示一个数据帧的结束,通常有 1 位或 2 位。
校验位用于检查数据传输过程中是否出现错误,有奇校验、偶校验和无校验等方式。
那么,如何在单片机中编程实现串口通信呢?以常见的 51 单片机为例,我们需要先对串口进行初始化设置。
这包括设置波特率、数据位、停止位和校验位等参数。
然后,在发送数据时,将要发送的数据写入特定的寄存器,单片机就会自动将数据通过串口引脚发送出去。
接收数据时,单片机会自动将接收到的数据存放到特定的寄存器中,我们只需要从这个寄存器中读取数据即可。
在实际应用中,串口通信有着广泛的用途。
比如,我们可以通过串口将单片机采集到的数据发送到电脑上进行分析和处理。
又或者,我们可以通过串口接收来自电脑或其他设备的控制指令,从而实现对单片机系统的远程控制。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
51单片机的串口,是个全双工的串口,发送数据的同时,还可以接收数据。
当串行发送完毕后,将在标志位TI 置1,同样,当收到了数据后,也会在RI 置1。
无论RI 或TI 出现了1,只要串口中断处于开放状态,单片机都会进入串口中断处理程序。
在中断程序中,要区分出来究竟是发送引起的中断,还是接收引起的中断,然后分别进行处理。
看到过一些书籍和文章,在串口收、发数据的处理方法上,很多人都有不妥之处。
接收数据时,基本上都是使用“中断方式”,这是正确合理的。
即:每当收到一个新数据,就在中断函数中,把RI 清零,并用一个变量,通知主函数,收到了新数据。
发送数据时,很多的程序都是使用的“查询方式”,就是执行while(TI ==0); 这样的语句来等待发送完毕。
这时,处理不好的话,就可能带来问题。
看了一些网友编写的程序,发现有如下几条容易出错:1.有人在发送数据之前,先关闭了串口中断!等待发送完毕后,再打开串口中断。
这样,在发送数据的等待期间内,如果收到了数据,将不能进入中断函数,也就不会保存的这个新收到的数据。
这种处理方法,就会遗漏收到的数据。
2.有人在发送数据之前,并没有关闭串口中断,当TI = 1 时,是可以进入中断程序的。
但是,却在中断函数中,将TI 清零!这样,在主函数中的while(TI ==0);,将永远等不到发送结束的标志。
3.还有人在中断程序中,并没有区分中断的来源,反而让发送引起的中断,执行了接收中断的程序。
对此,做而论道发表自己常用的方法:接收数据时,使用“中断方式”,清除RI 后,用一个变量通知主函数,收到新数据。
发送数据时,也用“中断方式”,清除TI 后,用另一个变量通知主函数,数据发送完毕。
这样一来,收、发两者基本一致,编写程序也很规范、易懂。
更重要的是,主函数中,不用在那儿死等发送完毕,可以有更多的时间查看其它的标志。
实例:求一个PC与单片机串口通信的程序,要求如下:1、如果在电脑上发送以$开始的字符串,则将整个字符串原样返回(字符串长度不是固定的)。
2、如果接收到1,则将P10置高电平,接收到0,P10置低电平。
(用来控制一个LED)单片机是STC89C52RC/晶振11.0592/波特率要求是9600或4800。
谢谢!问题补充:可能会将【$ABCD,123456,987654ccc,aasdasd,aaaa,sssd,4D】这样的字符串(字符串长度约为50-150个字符)传送给单片机,只能能原样返回。
[cpp]view plaincopy1.最佳答案:2.下列程序,已经调试成功。
3.#include <REG52.H>4.sbit LED = P1^0;5.unsigned char UART_buff;6.bit New_rec = 0, Send_ed = 1, Money = 0;7.//----------------------------------------------8.void main (void)9.{10. SCON = 0x50; //串口方式1, 8-n-1, 允许接收.11. TMOD = 0x20; //T1方式212. TH1 = 0xFD; [url=]//******************[/url]13. TL1 = 0xFD;14. TR1 = 1;15. ES = 1; //开中断.16. EA = 1;17.while(Money == 0); //等着交费,呵呵,等着接收$.18.while(1) {19.if ((New_rec == 1) && (Send_ed == 1)) { //如果收到新数据及发送完毕20. SBUF = UART_buff; //那就发送.21. New_rec = 0;22. Send_ed = 0;23. } }24.}25.//----------------------------------------------26.void ser_int (void) interrupt 427.{28.if(RI == 1) { //如果收到.29. RI = 0; //清除标志.30. New_rec = 1;31. UART_buff = SBUF; //接收.32.if(UART_buff == '1') LED = 1;33.if(UART_buff == '0') LED = 0;34.if(UART_buff == '$') Money = 1;35. }36.else { //如果送毕.37. TI = 0; //清除标志.38. Send_ed = 1;39. }40.}41.//----------------------------------------------/BLOG_ARTICLE_3007162.HTM串口接收程序是基于串口中断的,单片机的串口每次接收到一字节数据产生一次中断,然后再读取某个寄存器就可以得到串口接收的数据了。
然而在实际应用当中,基本上不会有单字节接收的情况。
一般都是基于一定串口通信协议的多字节通信。
在422或者485通信中,还可能是一个主机(一般是计算机)带多个从机(相应的有单片机的板卡)。
这就要求我们的单片机能够在连续接收到的串口数据序列中识别出符合自己板卡对应的通信协议,来进行控制操作,不符合则不进行任何操作。
简而言之就是,单片机要在一串数据中找到符合一定规律的几个字节的数据。
先来说下怎样定串口协议吧。
这个协议指的不是串口底层的协议,而是前面提到的数据帧协议。
一般都是有帧头(2~3个字节吧),数据(长度根据需要),结束位(1位,有时候设计成校验字节,最简单的校验也就是前面所有数据求和)。
比如0xaa 0x55 +(数据部分省略)+校验和(除了aa 55 之外数据的和),如果要是多板卡的话有时候还要在帧头后面加一个板选字节(相当于3字节帧头了)。
第一次写串口接收程序的时候,我首先想到的就是定义一个全局变量(实际上最好是定义局部静态变量),初始值设置为0,然后每进一次中断+1,然后加到串口通信协议的长度的时候再清零。
然后判断帧头、校验。
写完了之后我自己都觉得不对,一旦数据错开了一位,后面就永远都接收不到数了。
无奈看了一下前辈们的代码,跟我的思路差不多,只不过那个计数值跟接收到的数据时同时判断的,而且每次中断都要判断,一旦不对计数的那个变量就清零。
废话少说,直接上一段代码让大家看看就明白了。
(通信协议姑且按照简单的aa 55 一个字节数据一个字节校验,代码是基于51单片机的)。
接收成功则在中断程序中把串口接收成功标志位置1。
[cpp]view plaincopy1.然后串口中断部分2.void ser()interrupt 43.{4.static unsigned char count;//串口接收计数的变量5. RI=0;//手动清某个寄存器,大家都懂的6. receive[count]=SBUF;7.if(count==0&&receive[count]==0xaa)//同时判断count跟收到的数据8. {9. count=1;10. }11.else if(count==1&&receive[count]==0x55)12. {13. count=2;14. }15.else if(count==2)16. {17. count++;18. }19.else if(count==3&&receive[count]== receive [2])//判断校验和,数据多的话是求//和,或者其他的校验方法,也可能是固定的帧尾20. {21. count=0;22. uart_flag =1;//串口接收成功标志,为1时在主程序中回复,然后清零23. ES=0; //关中断,回复完了再ES=1;24. }25.else26. {27. count=0;//判断不满足条件就将计数值清零28. }29.}第一次做的串口大概就按照这个方法写完了(我后来看过其他的代码,有人用switch语句写的,逻辑跟这个也差不多,不过我还是感觉用if else来写清晰一些),不过在测试的时候发现了bug,如果数据帧发送一半,然后突然停止,再来重新发,就会丢失一帧的数据。
比如先接受到aa 55,然后断了,再进来aa 55 01 01,就不受控制了。
后来我也想到一个bug,如果在多设备通信中,属于其他设备的的帧数据最后一位是aa(或者最后两位为aa 55 ,或者最后3位为aa 55 板选),下一次通信的数据就接收不到了。
当时对于数据突然中断的bug,没有想到很好的解决办法,不过这种情况几率极小,所以一直用这个方法写也没有问题。
多设备通信最后一位恰好是aa的几率也很小,出问题的可能也很小。
当时项目里面的控制数据跟校验恰好不可能出现aa,于是我把if(count==0&&receive[count]==0xaa)改成了if(receive[count]==0xaa)其他都没变,解决了,没有bug了。
后来我又写了几次单片机程序,才想到了一些解决问题的方法——不过改天再接着写吧,太累了,明天还要上班呢。
在后来的项目中,真的遇到了数据位跟校验位都可能出现aa的情况。
我考虑到每次数据都是连续发送的(至少我们用labwindows做的上位机程序是这样的),成功接收到了一帧数据是要有一定时间回复的,也就是说如果接收到一半,但是很长时间没接收到数据,把计数值count清零就ok啦。
涉及时间的问题自然要用定时器来实现啦。
这次的通信协议如下,串口波特率19200,2个帧头aa 55 ,一个板选,6字节数据,一个校验字节(除帧头外其他数据的和)。
[cpp]view plaincopy1.全局变量定义2.unsigned char boardAddr;//板选地址,通过检测几个io引脚,具体怎么得到的就不写了,很简单的3.unsigned char g_DatRev [10]={0};//接收缓存4.bit retFlag=0;//为1代表串口接收到了一帧数据5.6.7.串口初始化函数,晶振22.11848.9.void init_uart()10.{11. SCON = 0x50; //串口方式1允许接收12. TMOD = 0x21; //定时器1,方式2,8位自动重载,同时配置定时器0,工作方式113. PCON = 0x80; // 波特率加倍14. TH1 = 0xfa;15. TL1 = 0xfa; //写入串口定时器初值16. TH0=(65536-2000)/256; //写入定时器0初值,串口传输一个字节时间为(1/19200)*10,计算得0.52ms17. TL0=(65536-2000)%256; //定时器0定时大约1ms多18. EA=1;19. ET0=1; //波特率:19200 22.1184M 初值:250(0xfa)20. IE |= 0x90;21. TR1 = 1;22.}23.24.串口中断函数25.26.void UART_INT(void) interrupt 427.{28.static unsigned char count;//串口接收计数的变量29.30. RI = 0;31. g_DatRev[count] = SBUF;32.if(g_DatRev[count]==0xaa&&count==0) //帧头33. {34. count=1;35. }36.else if(count==1&&g_DatRev[count]==0x55)37. {38. count=2;39. }40.41.else if (count==2&&g_DatRev[2] == boardAddr)42. {43. CK = g_DatRev[count];44. count=3;45.46. }47.48.else if(count>=3&&count<9)49. {50.51. CK += g_DatRev[count];52. count ++;53. }54.55.else if(count == 9&&CK==g_DatRev[9])56. {57. ES = 0;58. retFlag = 1;59. count=0;60. }61.else62. {63. count=0;64. }65. resettimer();66.67.}68.69.//判断count不为0的话就启动定时器70.void resettimer()71.{72. TR0=0;73. TH0=(65536-2000)/256;74. TL0=(65536-2000)%256;75.if(count!=0)76. {77. TR0=1;78. }79.}80.81.定时器中断函数82.void T0_time()interrupt 183.{84. TR0=0;85. TH0=(65536-2000)/256;86. TL0=(65536-2000)%256;87. count=0;88.89.}这种方法的确是本人自己想出来的,别人可能也这样做过,但我这个绝对不是抄袭或者模仿来的。