前言:上位机和单片机串口通信通常是采用帧来传输的,并非一个字节一个字节的来接受判断,一般有3种情况:
(1) 一问一答,比如modbus通信协议就是这种方式
(2) 上位机发送启动命令,下位机不停的吐数据给上位机,上位机发送停止命令,下位机才不发送数据.
(3) 下位机只要开机,就会一直吐数据给上位机,上位机只需要不停接收数据,并解析即可。
不管是哪种情况,都有一个共性,那就是传输命令是以帧为单位,而非一个字节。
================================================================
本文是针对STC89C52单片机来说明,如果是STM32 可以直接利用空闲中断就好,不需要像51这么复杂。
在实际运用中,做上位机和下位机通信的项目,要先设计好双方认可的通信协议,然后根据协议来写串口代码。上位机发送不同的指令(每一个指令就是一帧数据),单片机对应执行不同的功能。
(1)帧定义方法
串口命令一般由5部分组成
帧头+长度+功能定义+有效数据+校验+帧尾
根据实际应用,校验和帧尾可以加上,也可以去掉,比如如下所示
(2)如何区分一帧命令发送完成
当需要发送一帧数据时,这些数据是连续不断的发送的,发送一个字节,马上发送下一个字节,中间没有间隔。当这一帧发送完成之后,发送下一帧数据的时候和这一帧数据必定存在一定的时间间隔,换句话说,每一帧数据之间会存在一段总线空闲时间,于是,我们可以设置一个定时器,这个定时器一直在计数,当接收一帧数据里的字节时来时,就不停的清零,当一帧结束,总线空闲后,没有接收数据,定时器就会一直累加,当累计到一定超时时间,比如20ms(根据实际情况修改空闲时间)时,我们就认为一帧完整的数据已经传输完毕。此时就可以设定帧接收标志置位,下位机就可以对这一帧数据进行分析了。
因为涉及到计时,会需要写一个串口空闲时间监控函数static void Uart_RxMonitor(uint8_t); 放到定时器中断函数中计数。
(3)串口的驱动库一般包含如下内容
发送字节函数,发送半字函数,发送数组函数,发送字符串函数,读取接收缓冲区数据函数
这几个函数,实际运用的时候,就会经常被调用。
代码解析如下:
(1)定时器中断函数中放入空闲时间监控函数uart.RxMonitor(RX_IDLE_TIME_TICKS); RX_IDLE_TIME_TICKS是宏定义,表示空闲时间累计到多长,就认为是一帧数据发送完毕了。
(2)串口中断函数,如果是接收中断,就把一个个数据放入接收缓冲区,如果是发送中断,就要清除中断标志
(3)串口头文件宏定义,以及定义串口结构体
(4)所有uart.c驱动代码参考如下
(5)Uart_Rx_Process函数用进行对一帧数据进行处理的功能函数,要放在一个循环中,当帧标志位置有效,就可以执行这个函数里面的功能。
其他功能函数调用方法如下,以数组为例
uart.SendArray(arr);
以上所有代码全部是在STC89C52单片机调试过,均可正常使用。