STM32串口通信程序模拟超市打印机工作-使用接收中断、空闲中断、校验中断

本文详细介绍了一个基于STM32单片机的串口通信项目,模拟超市收银台电脑与打印机的通信流程。项目实现了RS232串口通信,包括硬件电路搭建、软件编程、中断处理、数据解析与串口输出等功能,旨在深入理解串口通信原理。
摘要由CSDN通过智能技术生成

项目代码资料请移步:https://download.csdn.net/download/lishan132/12420086

Gitee 项目资料    https://gitee.com/lishan666/Usart

1 项目简介

        超市的收银台一般都会放置一台小型打印机,其任务是将顾客的消费金额等信息打印在一张小票上。那么打印机又是如何知道自己该打印那些内容呢?本文以经典的RS232串口通信来模拟收银台电脑与打印机之间的通信工作流程。

  1. 用笔记本电脑模拟收银台电脑,串口通信助手为上位机界面;
  2. 用STM32F103C8T6单片机作为打印机控制器;
  3. 用PL2303HX模块完成USB到TTL电平的转换;
  4. 在串口通信助手发送区输入打印指令并发送;
  5. 在串口通信助手接收区显示打印结果及提示信息。

    值得一提的是,超市收银台电脑与打印机之间的通信方式不止RS232串口一种,常见的还有USB通信、LPT并口通信、WiFi通信等方式。它们本质上都是一种数据传输手段,只不过其工作方式、成本、实现复杂度等有所区别。

       为了将所学的串口通信知识与实践相结合,现在通过开发一个实际的项目来掌握串口通信的核心要点及开发流程,实现由理论知识到实际应用的转变,本文对超市微型打印机的通信部分进行研究设计。设计目标是:

(1)搭建电脑到打印机之间的RS232串口通信电路;

(2)设计串口通信程序,程序运行在打印机控制器STM32F103C8T6中;

(3)通过串口调试助手对通信效果进行演示。

2 设计要求

基础部分

串口通信的具体设计要求如下:

(1)波特率4800bps,一位起始位,八位有效数据位,一位奇偶校验位;

(2)使用串口调试助手发送一个数据打印命令“@PrintData12345678900#”;

(3)单片机收到命令后,解析命令,输出数据“1234567890”,然后给上位机发送“数据已成功打印”。

扩展部分

为了加深对串口通信知识的理解和运用,本文提出以下扩展要求并进行实现:

(1)每次输出打印信息及提示信息结束后都进行换行显示;

(2)系统上电工作时,通过串口通信助手显示系统正常工作的提示信息;

(3)当打印指令错误时,输出“instruction error”进行提示;

(4)当接收的字符数大于设定的缓冲区大小时,输出“Overflow error”;

(5)当出现校验错误时,输出“校验错误,请重新发送命令”。

3 总体设计方案

       使用笔记本电脑与STM32单片机进行数据交互,模拟超市电脑与打印机之间的通信过程。笔记本电脑上安装有串口调试助手软件,串口调试助手作为上位机可以实现人机界面交互的功能,同时也是检验串口通信是否正常的工具。

      笔记本电脑一般没有串口,但至少有一个USB口。单片机的串口是映射到GPIO上的,本文只需要用到接收、发送引脚,也就是2个GPIO,再加上电源和地,一共4个单片机引脚。笔记本的USB口和单片机串口之间不能直接相连,因为两者的工作电平逻辑不一致,需要通过一个USB转TTL模块进行电平转换,同时笔记本电脑上需要安装配套的USB转串口驱动程序。

 

系统设计方案

4 设计前的思考和准备

思考:

1、串口的参数设置中有一位校验位,如何实现,又如何体现校验的作用;

2、如何判断串口数据传输的开始、结束;

3、如何判断命令是否符合要求,并取出中间的数据部分;

4、能否直接输出中文。

准备:

  1. 搭建硬件电路连线

        在开发过程中,本文还连接了ST-Link调试器,使用调试器可以让程序下载更快,同时能进行硬件仿真调试,可以提高开发效率,当然也可以直接使用串口下载程序。项目完成后,实际运行时不需要再连接调试器。

                                                                

硬件连接

      2.安装USB转串口驱动程序

        本文用到的USB转TTL模块芯片为PL2303HX,驱动程序可在网上进行下载,双击驱动程序按提示完成驱动安装。其他芯片的驱动安装方法类似。

安装USB转串口驱动

        驱动安装完成后,插上USB转TTL模块,在设备管理器中选择端口,如果能够看到识别到的驱动程序和端口号,表示驱动安装成功。否则,右键选择更新驱动程序,从我的计算机驱动程序中选择2009年的版本,当出现下图界面,能分配到一个端口号即表示安装成功。其它的芯片模块可能在驱动程序安装完后就能看到端口号,此时不需要进行驱动程序的更新操作。

驱动安装成功示意图

     3.下载串口调试助手软件、Keil-MDk软件

      串口调试助手网上非常多,可以自行选择,但是要注意,一定要知道这款串口助手对中文字符的编码采用什么格式,网上资源以GB2313居多,也有部分是采用UTF-8格式的,本文选择GB2313编码方式的串口调试助手。

      Keil-MDK软件是开发嵌入式的IDE,可从网上下载,建议下载5.28版本,破解操作也可从网上参考,本文不赘述。Keil-MDK编程的编码格式设置一定要与串口调试助手一致,这样才不会出现中文乱码的问题,建议选择GB2313。

MDK-keil编码设置

    4.准备一份STM32中文参考手册,便于开发过程中查询串口的使用方法以及相关寄存器的设置。

    5.准备一份STM32固件库手册,便于开发程序时查询标准固件库函数使用方法,加快开发效率。

    6.找到一份STM32工程模板文件,可以直接从固件库文件中复制,也可以自己创建,省去工程的创建、文件的添加等机械工作。

准备资料

5 本文设计的关键点

5.1 校验位设置

通过查阅STM32中文手册发现,USART_CR1寄存器中的PCE位可以使能奇偶校验位的产生,M位可以设置数据字的长度,如下图所示:

 

USART_CR1寄存器PCE位-决定是否产生校验位
USART_CR1寄存器M位-决定数据字长度

       M位和PCE位的值两者共同决定USART帧的格式,一共四种,如下图所示。根据设计要求,本文设置为M位为1,PCE位为1,即字长为9,校验位选择奇校验(也可选择偶校验)。

 

校验控制串口帧格式

        通过查阅STM32固件库手册,复制串口参数设置代码示例,并进行修改,下面展示关键部分的参数设置。

 

串口初始化参数设置

5.2 串口中断设置

      串口通信的数据接收、发送程序一般有中断和查询(也叫轮询)两种方式,相对来说,中断方式对CUP的资源占用较少,响应也更及时,本文使用中断方式接收来自上位机电脑的数据。

      翻阅STM32中文手册发现,STM32单片机的串口中断请求事件有以下几种,当表中事件发生时,只要设置了相应的中断使能,都会通过嵌套中断向量(NVIC)的向量表进入到串口中断服务程序中,可以在服务程序中查询相应事件的标志位判断当前是那一种事件发生。为了检测数据的接收、接收完成、奇偶校验出错这三种情况,本文设置的三个串口中断事件,下图中用红框标注。

①接收数据就绪可读表示对方已经发送了一个字节数据,这个数据现在在硬件接收缓冲区中,并且现在可以读出数据。当第一次发生此事件时代表数据传输的开始。

②检测到空闲线路表示在对方传输上一字节数据后,又过了一个字节的传输时长,单片机仍然没有接收到数据,可以代表数据发送的结束,也就是完成了一次数据的传输。

③奇偶校验错表示按照约定的校验规则,当前字节的数据发生了错误。

STM32串口中断事件 (注:表中的TXNE标志应为RXNE)

 

根据固件库手册和库函数注释,使能上述三个串口中断事件的代码如下:

使能串口中断事件

 

5.3 串口中断服务程序

        根据STM32中文手册,串口中断事件相应的标志位在状态寄存器SR中,在串口中断服务程序中查询这几个标志位的值就可知道发生了什么事件。SR寄存器中的三个标志位介绍如下所示:

 

串口中断标志位及清除方法

        从上表看出,标志位置1时,表示该事件发送,此时单片机可以进行相应操作。但要注意,一定要及时清除标志位(清0操作),否则程序会一直进入中断服务程序。对于RXNE位,当读出DR寄存器中的数据后,硬件自动清0,不用再单独写清0的代码。对于PE位和IDLE为,需由软件进行清0,清0操作为先读SR寄存器,再读DR寄存器。串口1软件清除PE、IDLE标志位代码为:

USART1->SR;  //先读状态寄存器

USART1->DR;  //再读数据寄存器

         串口1的中断服务程序名为void USART1_IRQHandler(void),位于stm32f10x_it.c文件中,当然,也可以写在其他位置,但程序名不要改变,同时要处理好各c文件之间依赖关系。

 串口中断服务程序

 

6 程序设计

在本文的程序设计中,要注意以下几个要点。

  1. 有奇偶校验位时,串口初始化程序中的字长设置为9,串口调试助手中的数据位选择8;
  2. 注意各种标志位的设置与清除,串口发送完数据后一定要等TXE置位后再发送下一位数据;
  3. 主函数、中断请求函数中不宜写太多代码;
  4. 可以考虑在解析数据前关闭中断,串口输出数据后再打开中断。

整个程序有四个关键部分,分别是主函数、串口中断处理、数据解析、串口输出,下面分别对它们的流程做简单介绍。串口输出和数据解析函数放在附录中。

6.1 主函数

主函数流程图

 

主函数程序展示图

 

6.2 串口中断处理函数

串口中断处理函数流程图

 

接收中断回调函数

 

空闲中断回调函数

 

校验出错中断回调函数

6.3 数据解析函数

数据解析函数流程

6.4 串口输出函数

 

串口输出函数流程

7 结果演示

     打开串口调试助手,设置好串口参数,按各种情况进行测试,演示效果如下

演示效果图

 

8 课堂问题解答

 

第19组第一个问题:开始和结束错误标志都设置为2会不会分不清?

答:因为指令的开始和结束部分出现错误时都表示这是一个错误的指令,所以程序中将其错误类型都设置为2,这样做确实是无法分清到底是指令的开始部分发生了错误还是结束部分发送错误。如果确实有必要将这两种错误分开,可以考虑在程序中将这两种情况设置不同的错误标志号。

 

第12组第一个问题:为啥选奇校验和偶校验哪个都对?

答:尚不清楚您说的对是什么意思,但是不管在串口助手中选哪一种校验方式,发送指令后单片机都会返回一段信息,可能是成功打印的信息,也可能是错误的提示信息。在演示中出现了一个细节可能与您的提问相关,因为当时发送的是一个错误的指令,所以不管选择奇校验还是偶校验方式,单片机返回的信息都是“instruction error”,这是由于程序中必须对数据进行解析,当解析结果为指令错误时,其错误码为2,也就是输出“instruction error”。换句话说,当出现多种错误时,优先考虑指令是否错误。当发送一个正确的指令时,在串口助手中选择与程序设计中不同的校验方式,就会输出“校验错误,请重新发送命令”。

 

第2组第一个问题:自己设定的三个中断有优先级的考虑吗?

答:程序中设置有接收中断、空闲中断、奇偶校验出错中断,但这三个中断本质上都属于串口中断,只不过这是引起串口中断的三种不同事件,当任意一件事件发生时,都会进入同一个串口中断服务函数,可以在中断服务函数中判断对应的标志位是否置1,进而确定是哪一个事件的发生导致进入了串口中断服务函数。因为不可能有两个及以上的事件同时发生,所以这三个中断事件之间不存在优先级的问题。另外,因为整个程序只用到了一个串口中断,不存在其它外设中断源,所以也可以不用对中断优先级进行设置。

 

第5组第一个问题:可以详细讲解一下中断的过程吗,比如各个中断的优先级,以及如果在主函数解析时中断关闭的方式等

答:一个外设(比如定时器、串口)要发生中断有三个条件,一是使能了外设,可类比为电路中的干路总开关;二是打开了中断使能位,可类比为支路的第一个开关(有多种事件可触发串口中断,可看成是多条支路);三是对应事件的中断标志位置1(一般是硬件自动置1),可类比为支路第二个开关,只有三个开关全部合上,才会进入中断服务函数。

当发生中断时,程序会保存当前的数据和指令执行位置等信息到堆栈,称为现场保护。这个堆栈空间是硬件自动开辟的,数据的保存也是自动完成的,不需要在程序中再进行任何操作。保存完毕后,程序会查询中断向量表,向量表上保存的是各个中断的服务程序的起始地址,通过此地址可跳转到中断服务中执行中断服务体内的程序,当离开中断服务程序时,程序会从堆栈中弹出数据,返回到进入中断前的指令位置,继续执行当前程序。

中断的优先级一般指的是不同中断源之间的优先级别高低,比如程序中存在定时器中断和串口中断,那么这两个中断可能会同时触发,或者正在串口中断服务程序中执行时,定时器中断又被触发。当发生这些情况时,如果没有相应的处理机制,系统将会陷入混乱。由此引入的中断优先级的概念,即将每个中断源都设置一个优先级别,这样,遇到上述情况时,就可以根据优先级的高低来决定当前去处理那一部分的程序。如果优先级一样,或者在程序中没有设置中断优先级,那么系统会根据向量表中默认的优先级进行处理。

STM32中文手册中的第9章可以查看中断的相关信息,串口1中断的默认优先级为44。

       STM32通过4位数据对优先级进行编程设置,在程序中设置中断优先级时,有优先级分组、抢占优先级和响应优先级三个参数设置,系统复位后默认的中断优先级优先级分组设置为0,即全部用于响应优先级,不存在抢占优先级。详情见STM32固件库手册,本文不再赘述。在本文程序的主函数中解析数据时,如果要关闭中断,只需要关闭上面提到的三个开关中任意一个即可,最简单的就是直接失能串口外设,其代码为:

USART_Cmd(USART1, DISABLE);    /* 失能USART1 */

当输出数据后,可以再次开启串口,进行下一次的接收。

第9组第一个问题:如何编写中断服务函数

答:进入中断服务函数后,首先是对标志位进行判断,确认中断事件,然后是标志位的清除,避免一直进入中断服务函数。接下来有两种思路,一是将发生该中断事件时需要处理的逻辑代码全部放在该程序中,比如数据的保存、LED等的亮灭等等,执行完毕后退出中断服务函数;二是设置一个标志位,然后在主函数的while循环中判断此外部变量标志位的值,进而进行相关操作。

 

第21组第一个问题:解析数据时关闭中断这样会不会有后续数据的丢失?

答:分两种情况,如果在解析数据时,又从上位机发送了数据到单片机,那么这部分数据会丢失,因为中断已经关闭,无法进入中断服务函数,数据根本无法接收,只会在硬件缓冲区一次又一次的被覆盖。如果在解析数据时没有新的数据传输到单片机,等解析完毕后,中断再次打开时,才有数据传输过来,那么对数据是没有任何影响的。当然,单片机处理数据的数据还是比较快的,如果上一次传输的数据比较少,解析数据的时间花费少,中断可以很快再次打开,那么是感觉不到什么影响的,如果一次传输大量数据,在下一次传输时就可能存在丢失数据的情况,也就是丢包。

 

第4组第一个问题:当数据进入中断的时候,主函数是在等待吗?如果是的话中断函数比较多,怎么保证当中断结束时主函数能从原来的位置直接运行?

答:当进入中断时,主函数的确是处于等待状态,但第二个问题不需要担心,每一次进入中断时,硬件会自动进行现场保护,也就是开辟堆栈空间,保存当前的状态信息,当然也包括当前指令执行的位置,中断服务函数结束后,数据从堆栈中弹出,程序回到进入中断前的现场,继续执行。整个过程都是硬件自动完成,程序员不用做任何操作。

 

第5组第二个问题:如果传输数据中,出现终止符怎么办?

答:一般不会在串口助手中发送终止符,字符串终止符(也就是空字符)的Ascii码为0x00,在本文程序中,如果出现终止符,后续数据也是能够接收的,即能够保存在数组中。但是在单片机的串口发送函数中,遇到空字符就会认为数据已经结束,后续的数据不会被发送。遇到这种问题,暂时没有一个好的解决方案,可以考虑修改串口发送函数,不再以是否为空字符为结束标志,而是确定一个明确的数据长度。

 

第18组第一个问题:程序中字符串的发送是怎么实现的?

答:程序中的字符串发送没有用到任何中断,当然也可以使用中断,在中断服务函数中再调用数据发送函数。库函数void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)可以实现通过串口发送引脚TX,发送1字节数据的功能,第一个参数为串口号,第二个参数为发送的数据,因为STM32中的串口发送数据的字长有8位和9位两种,所以此参数类型为uint16_t,即16位。但是一般8位最常用,因为刚好一个字节,9位的用得较少。发送数据后需要等待当前数据发送完成才能进行下一次的发送,也就是等待发送完成标志位TC置1,代码为:

while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET);

为了实现字符串的发送,也就是多个字节连续发送,可定义一个函数,如下:

void Send_data(uint8_t *data)
{
    while(*data!='\0')
    {
      while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET);

      USART_SendData(USART1,*data);

      data++;
    }
}

当没有到达字符串的结束标志’\0’之前,循环调用数据发送函数,同时指针移到下一位。值得注意的是,如果使用了串口发送功能,那么最好在串口初始化函数usart1_init()中最后加一句清除发送完成标志的代码,如下:

USART_ClearFlag(USART1,USART_FLAG_TC);    //清除发送完成标志位

第2组第二个问题:除了数字还可以发送其他信息吗?

答:可以的,传输的数据在传输线上就是一个个的高低电平,在单片机内部就是01...这种的二进制数,将其用不同的译码规则翻译就是不同的信息。一般将其保存到字符数组中,也就是字符类型,符合Ascii码规则,包含了数字、字母、特殊字符等信息。

 

第24组第一个问题:一次发送数据的上限是多少?

答:理论上是没有限制的,也就是单片机的串口可以连续工作,一直发送、接收数据,实际使用时通常在软件中定义一个缓冲数组,数组的大小就决定了一次发送数据的上限。本程序中定义大小为100。

 

第5组第三个问题:@printdata12345678900#多次与@printdata12345678901234567890...12345678900#数据传输的差别可以说一下么?

答:@printdata12345678900#多次,例如发送@printdata12345678900#@printdata12345678900#@printdata12345678900#时,按照本文程序的设计思路,依次检查首尾指令,符合要求,将会正确打印中间数据部分,即打印12345678900#@printdata12345678900#@printdata1234567890

   发送@printdata12345678901234567890...12345678900#时,同样检查首尾指令,符合要求,将会正确打印中间数据部分,即打印12345678901234567890...1234567890

 

第24组第二个问题:在stm32端奇偶校验位要算在数据位中,在PC端奇偶校验位是否要算在数据位中?

答:这个与PC端串口调试助手开发的源码有关系,但是大部分软件都是如果在软件界面的数据位选择为8位,校验位选择奇检验或偶校验,那么调试助手会将接收到的数据的低8位作为数据位,最高位单独取出作为校验位。所以一般来说,PC端奇偶校验位不算在数据位中。

### 回答1: STM32F103的串口空闲中断接收是指当串口接收数据完成,且一段时间没有接收到新的数据时,会产生空闲中断。 在使用STM32F103的串口空闲中断接收时,首先需要设置串口的工作模式为中断接收模式,并使能串口的空闲中断。可以通过配置串口的控制寄存器来实现这一设置。 当串口接收到数据时,会触发中断服务程序。在中断服务程序中,需要读取接收数据寄存器的数据,并进行处理。可以将接收到的数据存储到缓冲区中,或者执行相应的操作。在处理完数据后,还需要清除空闲中断标志位,以便下次空闲中断能正确触发。 通过使用串口的空闲中断接收,可以实现串口数据的及时处理。相比于轮询方式,空闲中断接收可以减少CPU的占用率,并且能够在数据接收完成后立即进行处理,响应速度更快。 需要注意的是,使用空闲中断接收需要合理设置串口的波特率和合适的时间间隔。同时,还需要根据具体应用场景,合理设计缓冲区的大小,以免数据丢失或者溢出。 总之,STM32F103的串口空闲中断接收能够有效地实现对串口数据的及时处理,提高系统的响应速度和效率。 ### 回答2: 当STM32F103的串口接收到数据时,它可以通过串口空闲中断来进行处理。串口空闲中断是指当串口停止接收数据一段时间后,触发的中断事件。 在使用串口空闲中断接收数据之前,我们需要进行一些设置。首先,确保串口的接收使能位已经打开。然后,按照需求设置串口的波特率、数据位、停止位等参数。 接下来,我们需要将串口空闲中断使能位打开。这可以通过设置USART_CR1寄存器的IDLEIE位来实现。这样,当串口接收到数据后一段时间内没有新的数据进来,就会触发串口空闲中断。 在中断服务程序中,我们可以读取USART_SR寄存器的IDLE位来判断是否是串口空闲中断。如果是,我们可以使用USART_DR寄存器来读取接收到的数据。 为了继续接收数据,我们需要在中断服务程序中进行一些操作。可以重新打开接收使能位,以便继续接收新的数据。我们也可以清除空闲中断标志位,以便下一次空闲中断的触发。 需要注意的是,在中断服务程序中处理数据时,应该尽量避免阻塞操作。如果需要进行繁重的数据处理,可以考虑使用缓冲区或者DMA来处理接收到的数据。 总之,通过配置和操作USART_CR1、USART_SR和USART_DR寄存器,我们可以实现STM32F103的串口空闲中断接收功能。 ### 回答3: STM32F103是一款ARM Cortex-M3内核的微控制器,支持串口通信功能。串口空闲中断接收是指当串口空闲时,通过中断的方式接收数据。 串口通信是一种常见的数据传输方式,它通过发送和接收数据来实现设备之间的通信。在STM32F103中,可以通过配置寄存器和使能中断来实现串口通信,并使用空闲中断接收数据。 首先,需要配置串口的相关寄存器。通过设置波特率、数据位、奇偶校验位、停止位等参数来确保串口通信的正确性。同时,还需要使能串口的接收中断和使能串口的空闲中断。 然后,当串口接收到数据时,会触发接收中断。在中断服务函数中,可以通过读取数据寄存器来读取接收到的数据,并进行相应的处理。若接收到的数据不需要立即处理,可以将其保存在缓冲区中,待后续处理。 当接收完成后,如果一段时间内没有再接收到新的数据,则会触发空闲中断。在空闲中断服务函数中,可以判断数据是否接收完成,并进行相应的处理操作。这种方式可以有效地提高串口通信的效率和稳定性。 总结而言,STM32F103支持串口空闲中断接收数据。通过配置相关寄存器和使能中断,可以实现当串口空闲接收数据,并通过中断服务函数进行处理。这种方式可以提高串口通信的效率和稳定性,适用于各种串口通信场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乐观的lishan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值