STM32串口通讯实际应用:串口屏控制详解

文章以UART基础知识和串口屏实际应用来说明串口的作用。

文章目录

  • 前言
  • 一、UART是什么?
  • 二、USART HMI
  • 1.引入字库和图片库
  • 2.控件与指令集的使用
  • (1)控件的事件编写
  • (2)STM32串口程序编写
  • 总结

  • 前言

    一、UART是什么?

    UART是通用异步收发传输器(Universal Asynchronous Receiver/Transmitter)的缩写,是一种串行通讯协议,通常用于将计算机或微处理器与其他设备(如传感器、模块、显示器等)进行通信。UART可以将数据以一定速率和格式(如数据位、校验位、停止位等)从发送器传输到接收器,从而实现双方的数据交换。常见的串口通讯协议如RS-232、RS-485等都是基于UART的。
    异步是什么意思?
    异步通信是指在通信过程中,数据的传输不依赖于时钟信号的同步。在异步通信中,数据是以字符为单位进行传输的,每个字符之间可能存在不等的时间间隔。通常使用UART协议来实现异步通信,其中发送端和接收端通过约定好的波特率、数据位、校验位、停止位等参数来进行通信。相对于同步通信,异步通信具有传输速率不受限制、成本低廉等优点,但也存在传输错误率高等缺点。
    USART
    USART是通用同步/异步收发传输器(Universal Synchronous/Asynchronous Receiver/Transmitter)的缩写,包含了UART的异步传输和同步传输两种模式。在异步模式下,USART与UART的通讯方式相同,支持异步串行数据传输,数据以字符为单位进行传输,每个字符之间可能存在不等的时间间隔;在同步模式下,USART可以将数据与时钟信号同步传输,数据和时钟信号的传输速率完全一致,并且不需要停止位,在传输速率较高的应用场景中,同步模式更为常用。USART可以支持多种数据格式和传输速率,具有较高的通信灵活性和可靠性
    并行与串行
    串行传输是指数据以一位一位的方式进行传输,每次只能传输1位数据,传输速度比较慢;并行传输是指多个数据位同时传输,每次可以传输多个二进制位,传输速度比串行传输快,但是需要使用更多的电线或光纤来传输数据。

    二、USART HMI

    适用于陶晶驰串口屏的上位机开发软件,无需代码即可完成屏幕内容DIY。

    1.引入字库和图片库


    这里可以选择引入图片、字库、动画等等,
    引入字库方法是:点击左上角工具:

    选择字库制作,弹出该界面,可自定义字高、编码方式和字体:

    点击所有语言,只选择CJK表意字符(目的是减少字符占用空间),

    自定义字库名称,保存后在左下角就会出现保存的字库。
    引入图片:
    较为简单,只需要点击左下角的加号,把你文件夹中的图片添加进来就可以。

    2.控件与指令集的使用

    这是串口屏使用的核心。这里以一个实例:串口屏设置按钮,发送特定信息给STM32,STM32接收后,根据指令控制LED亮灭。
    首先是HMI部分:

    界面如图,其中b0控件是按钮,t2文本控件,他的显示(熄灭或点亮)会随着LED状态而改变。

    (1)控件的事件编写

    这里,对LED按钮的弹起事件编写:printh 01,即按下串口屏的LED按钮并弹起后,将通过串口发送16进制的数据:0x01到STM32中去。对于t2文本控件,不做编写,t2控件的改变是接收STM32串口发送来的字符串数据而改变的,这是在stm32中编写。

    (2)STM32串口程序编写

    这里参考CSDN一位大佬的程序:首先进行串口配置(串口初始化),使用stm32的USART3,所以硬件连接应为
    RX————PB10
    TX————PB11
    先看头文件:

    #ifndef __USART3_H
    #define __USART3_H
    #include "sys.h" 
    
    void HMISendb(u8 k)	;
    void HMISends(char *buf1);
    
    void uart3_init(u32 bound);
    void USART3_IRQHandler(void);     	//串口1中断服务程序
    #endif
    

    这里声明了四个函数:
    1.uart3_init(u32 bound)

    void uart3_init(u32 bound)
    {
    	//GPIO端口设置
    	GPIO_InitTypeDef GPIO_InitStructure;
    	USART_InitTypeDef USART_InitStructure;
    	NVIC_InitTypeDef NVIC_InitStructure;
    	
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//时钟GPIOB、USART3
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
    	
    	//USART1_TX   PB10
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    	GPIO_Init(GPIOB, &GPIO_InitStructure);
    	//USART1_RX	  PB11
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    	GPIO_Init(GPIOB, &GPIO_InitStructure);  
    	
    	  //Usart1 NVIC 配置
        NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
    	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
    	//USART 初始化设置
    	USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
    	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    	USART_InitStructure.USART_StopBits = USART_StopBits_1;
    	USART_InitStructure.USART_Parity = USART_Parity_No;
    	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    	USART_Init(USART3, &USART_InitStructure);
    	
    	USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启中断
    	USART_Cmd(USART3, ENABLE);                    //使能串口 
    }
    

    和我文章第一讲的串口初始化基本一样,主要是对GPIO、USART、NVIC的配置。

    2.USART3_IRQHandler(void)

    void USART3_IRQHandler(void)   
    {
    	u8 Res;
    if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    		{
    		Res =USART_ReceiveData(USART3);	//读取接收到的数据
    			
    		if(Res==0x01)  LED_Flag=1;//若接收到数据为0x01,则LED标识符设置为1
            } 
    }
    

    函数中首先判断是否接收到数据(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET),如果接收到了数据,就调用USART_ReceiveData函数读取接收到的数据。

    接下来,使用if-else语句判断接收到的数据是哪个命令。如果接收到的数据是0x01,就将LED_Flag置为1,表示LED为高电平点亮状态。
    注意,这里要设置一个全局变量,用以判断LED当前状态:

    u8 LED_Flag=0;
    

    3.HMISendb(u8 k)

    void HMISendb(u8 k)		         //字节发送函数
    {		 
    	u8 i;
    	 for(i=0;i<3;i++)
    	 {
    	 if(k!=0)
    	 	{
    			USART_SendData(USART3,k);  //发送一个字节
    			while(USART_GetFlagStatus(USART3,USART_FLAG_TXE)==RESET){};//等待发送结束
    		}
    	 else 
    	 return ;
    
    	 } 
    } 
    
    

    该函数中使用了for循环,连续发送3次同样的字节。这是因为在HMI通信中,0xff是作为结束发送的信息的,也就是说,必须连续发送3次0xff作为结束传输的标志。
    具体而言,函数中使用了USART_SendData函数向USART3发送一个字节(k),然后使用while循环等待发送结束(USART_GetFlagStatus(USART3,USART_FLAG_TXE)==RESET)。在发送结束后,函数返回。如果传入的字节k为0,则直接返回,不进行发送。

    *HMISends(char buf1)

     void HMISends(char *buf1)		  //字符串发送函数
    {
    	u8 i=0;
    	while(1)
    	{
    	 if(buf1[i]!=0)
    	 	{
    			USART_SendData(USART3,buf1[i]);  //发送一个字节
    			while(USART_GetFlagStatus(USART3,USART_FLAG_TXE)==RESET){};//等待发送结束
    		 	i++;
    		}
    	 else 
    	 return ;
    
    		}
    	}
    

    函数中使用了while循环,不断发送字符串的每一个字符,直到遇到字符串结尾(‘\0’)为止。具体而言,函数中使用了USART_SendData函数向USART3发送一个字符(buf1[i]),然后使用while循环等待发送结束(USART_GetFlagStatus(USART3,USART_FLAG_TXE)==RESET)。在发送结束后,i自增1,继续发送下一个字符。如果遇到字符串结尾,则直接返回,不进行发送。

    总结

    本文仅对串口和HMI的基本设计进行了说明,下一篇文章我将写出STM32主程序,并详细分析STM32与HMI之间的串口通信方式,以及实物的实验效果。

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32串口通讯实际应用:串口屏控制详解

    发表评论