手势点灯任务二:利用python串口通信点灯

本文详细介绍了STM32串口通信的理论基础,包括通信协议、硬件电路连接、软件部分(如数据帧结构、波特率设置、时序控制)以及如何在STM32中驱动USART外设实现发送和接收。此外,还提到了Python串口通信的应用。
摘要由CSDN通过智能技术生成

任务二:串口通信


一、stm32串⼝通信理论部分

1、通信协议大总结

91810806173caa4241db82071ec493dd.png

  • 串口通信即为其中一种,其可以实现两个设备间的互相通信
  • 串口通信实现了各硬件模块的互相通信

2、串口通信硬件电路连接

其中:

  • GND接地(严格意义上讲也是GND数据线,传输数据依靠的是电平差)
  • VCC用于供电,若是两个设备均有单独供电,则不需要接这根线; 若需要供电,还要注意子系统的供电需求
  • TX与RX要交叉接(很好理解)
  • 若只需单工通讯,只接一根数据线即可
  • 若电平标准不一致,需要加装电平转换芯片
附:串口常用的电平标准
  • TTL电平:+3.3V或+5V表示1,0V表示0(一般用于单片机等小型设备)
    TX对地为3.3V,则为逻辑1;对地为0V,则为逻辑0
  • RS232电平:-3 ~ -15V表示1,+3 ~ +15V表示0(用于大型设备,所需电压高)
  • RS485电平:两线压差+2 ~ +6V表示1,-2 ~ -6V表示0(差分信号)(抗干扰能力强)

3、串口软件部分(串口时序、参数)

(1)串口参数
  • 数据帧:每个字节的存放地,由起始位、数据位和停止位组成
    数据位有8个代表一个字节的8位(还可能在最后有一个奇偶校验位)

  • 波特率:串口通信的速率(两个设备协调的统一通信速率)

  • 起始位:标志一个数据帧的开始,固定为低电平(空闲状态为高电平,起始位产生下降沿,来告诉设备要开始发送数据了)

  • 停止位:用于数据帧间隔,固定为高电平(为下一个起始位做准备,切换到高电平空闲状态)

  • 数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行

  • 比如:发送一个字节为0x0F,首先转化为二进制0000 1111,再低位先行:依次传入1111 000,可将整个过程理解为蛇进洞

  • 校验位:根据数据位计算得来,用于判断数据传输是否出错,出错可选择丢弃或者重传

    • 奇校验:发送方发送数据后,包括校验位在内的9个数据位会出现奇数个1

        原为0000 1111,则校验位补1,使1的个数为奇数
        原为0000 1110,则校验位补0,使1的个数为偶数
      

      接收方接收数据后,验证数据位和校验位中1的个数

    • 偶校验类似(保证1个数为偶数)

    • CRC校验法(循环冗余校验码)(网上查过,看不懂一点。。。)

(2)串口收发时序

开端位->数据位->校验位->中止位

  • 开端位,为一位逻辑0;
  • 数据位,可设为5-8位,由低位开端逐位发送;
  • 奇偶校验位,为一位,能够省掉;
  • 中止位,能够挑选1,1.5或2位,为逻辑1;
  • 闲暇时刻为逻辑1

二、学习并驱动stm32串口外设,实现串口发送和接受

1、USART简介

  • 很少在该串口中使用同步功能,故基本上与UART差不多

    同步功能多了一个时钟输出而已,甚至不支持时钟输入。。(不支持两个USART之间的同步通信)

  • 可以看作为两部分:接受和发送

    • 将数据寄存器中的一个字节的数据自动生成数据帧时序,从TX引脚发送出去
    • 自动从RX引脚接收数据帧时序拼接成一个字节数据,存放于数据寄存器
  • 自带波特率发生器最高达4.5Mbits/s(最常用:9600,115200)

  • 可配置数据位(8,常用/9)和停止位长度(0.5/1,常用/1.5/2)

  • 可选校验位(无校验、常用/奇校验/偶校验)

  • 持同步模式、硬件流控制(控制数据流量)、DMA、智能卡、IrDA(红外通信)、LIN(后三者属于其他协议)

  • stm32F103C8T6上共有3根USART的挂载线

2、USART结构

(1)串口数据的收发过程

  • 发送(TDR)/接收(RDR)数据寄存器:只读或只写
  • 发送移位寄存器:把字节的数据一位一位地移出去
    在发送移位寄存器中,要先等未发送的字节全部发送完毕,才能继续接入数据寄存器中的字节
  • 接收移位寄存器:一位一位接收,全部接收完成后一起进入数据寄存器中(也就是发送的逆过程,比较好理解)

(2)串口的控制系统


  • 发送器控制、接收器控制(顾名思义,很好理解)

  • 硬件流控管脚:控制数据流流入速率(一般不用)

    • nRTS:请求发送,为输出脚,接到对面的nCTS(告诉别人我能不能收)
    • nCTS:清除发送,是输入脚,接到外部设备的RTS用于接收别人nRTS的信号(查看别人是否可以接收)
  • 时钟引脚SCLK:产生同步的时钟信号,配合发送移位寄存器(一般不用)
    发送寄存器每移位一次,同步时钟电平就跳变一个周期

  • 唤醒单元:实现串口挂载多设备(一般不用)
    在USART地址处给串口分配一个地址
    当发送指定地址时此设备唤醒开始工作;
    当发送别的设备地址时别的设备工作,没收到地址的设备不唤醒保持沉默

  • 中断(输出)控制:TXE(发送寄存器空)和RXNE(接收寄存器非空)较重要
    用于判断发送、接收状态的必要标志位

(3)波特率发生器

  • 波特率发生器其实就是分频器

  • USART1挂载在APB2上(72MHz),其他的USART都挂载在APB1上(36MHz)

3、USART对应引脚

引脚模式USART1USART2USART3
TXPA9PA2PB10
RXPA10PA3PB11

4、一些细节问题

(1)数据帧
  • 8位字长也可以设置有无校验位,一般为了发送完整字节都选择无校验。9位字长常选择有校验
  • 可配置停止位长度为0.5,1,1.5,2四种,本质是时长不同,一般选择1位
(2)输入数据策略
  • 起始位侦测:
    输入电路对采样时钟进行了细分,会以波特率的16倍频率进行采样,即在1位的时间里进行16次采样
  • 数据采样

    由于起始位侦测已经对齐了采样时钟,所以这里就直接在第8、9、10次采样数据位(为了保证数据可靠性连续采样3次)

5、串口的发送

(1)初始化流程
  • 开启时钟:将USART和GPIO的时钟打开
  • GPIO初始化:TX配置为复用输出,RX配置为输入
  • 配置USART:直接使用一个结构体,即可配置所有参数
  • 只发送:开启USART即可
    还要接收的话:可能还要配置中断,需要在开启USART之前,再加上ITConfig和NVIC的代码
(2)认识库函数
USART使用函数
USART_DeInit(USARTx);
//将USART寄存器重置为默认值
    
USART_Init(USARTx,&USART_InitStruct);
//根据结构体的参数配置来对USARTx外设进行初始化

USART_StructInit(USART_InitStruct);
//将USART_InitStructure结构体初始化

USART_ClockInit(USARTx, USART_ClockInitStruct)
void USART_ClockStructInit(USART_ClockInitStruct)
//用于时钟输出(不常用)
    
USART_Cmd(USARTx, NewState)
//使能或者失能USART外设
//eg:USART_Cmd(USART1 , ENABLE)

USART_ITConfig(USARTx,USART_IT,NewState)
//配置指定的USART中断
//eg:USART_ITConfig(USART1 , USART_IT_RXNE , ENABLE)

USART_DMACmd(USARTx,USART_DMAReq, NewState)
//使能或者失能USART的DMA请求
//eg:USART_DMACmd(USART1 , USART_DMAReq_Tx , ENABLE)

USART_SendData(USARTx, uint16_t Data)
//通过USARTx外设传输单个字节数据
uint16_t USART_ReceiveData(USARTx)
//返回由USARTx外设接收的最新数据
USART结构体初始化函数
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;//波特率
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//流控
USART_InitStructure.USART_Mode = USART_Mode_Tx;//串口模式
USART_InitStructure.USART_Parity = USART_Parity_No;//校验位(ODD奇校验,EVEN偶校验)
USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位
USART_InitStructure.USART_WordLength=USART_WordLength_8b;//字长
	    
USART_Init(USART1,&USART_InitStructure);
USART_Cmd(USART1,ENABLE);
发送函数的书写
void Serial_SendByte(uint8_t Byte){
	USART_SendData(USART1, Byte);
    //将Byte变量写入TDR
        
    //需要等待数据进入移位寄存器,所以需要等待一下标志位置1
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
	//即等待发送数据寄存器空标志位变为SET(置1后)
	//此时也不需要手动清零标志位,下一次SendData时会自动清零
    }
(3)代码书写注意
  • USART1是APB2的外设,其他都是APB1的(APB2性能高于APB1)
  • TX引脚是USART外设控制的输出脚,应选用复用推挽输出模式
    RX引脚是USART外设数据输入脚,应选择输入模式(一般浮空或上拉)
(4)不同数据模式
  • HEX模式/十六进制模式/二进制模式:以原始数据形式显示(显示一个个十六进制数)
  • 文本模式/字符模式:显示数据编码后的形式
    eg:发送0x41,HEX模式显示41,文本模式显示为A(ASCII码)
先实现下发送吧。。。

(这里的发送案例是发送单个字节)

  • serial.c
    serial.png
  • main.c
    main.png
    接上(库函数认识)
(5)发送数组
void Serial_SendArray(uint8_t Array[], uint16_t Length){
	uint16_t i;
	for (i = 0; i < Length ; i ++){
		Serial_SendByte(Array[i]);
	}
}
(6)发送字符串
void Serial_SendString(char String[]){
	uint8_t i;
	for (i = 0; String[i] != 0;i++){
		Serial_SendByte(String[i]);
	}
}
(7)发送一个数字
void Serial_SendNumber(uint32_t Number,uint8_t Length){
	uint8_t i;
	for (i = 0 ; i < Length ; i++){
		Serial_SendByte(Number / SerialPow(10,Length - i - 1) % 10 + '0');
	}
}
(8)对printf()函数重定向
int fputc(int ch, FILE *f){
	Serial_SendByte(ch);
	return ch;
}
(9)对sprintf()函数的封装
void Serial_Printf(char *format, ...){
	char String[100];
	va_list arg;//定义一个参数列表变量
	va_start(arg, format);//从format位置开始接受参数表,放在arg中
	vsprintf(String, format, arg);//打印位置String,格式化字符串format,参数列表arg
	va_end(arg);//释放参数表
	Serial_SendString(String);//把String发送出去
}

6、串口的接收

(1)利用查询接收数据
  • 流程:主函数中不断查询标志位(若置1,则说明收到数据)->调用recievedata读取DR即可
  • 这里我还是将函数进行了封装
void Serial_RecieveByte(uint8_t Byte){	
	if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET){
		Byte = USART_ReceiveData(USART1);
		OLED_ShowHexNum(1, 1, Byte, 2);
	}
}
(2)利用中断接收数据

(这里博主还没学,因为这个小项目暂时用不到)

三、学习python串口通信,⽤python实现串口发送和接受

1、为了使程序更简洁,我写了一个PC13.c和PC13.h方便函数调用

  • 这里参照的是LED.c和LED.h进行的书写,通过书写可进一步熟悉相关函数的调用

2、主函数的书写及遇到的问题

  • 关于不用中断读取DR中的值:使用输入寄存器标志位判断
  • 由USART_RecieveData()函数读取的值是ASK码,因此判断时应当使用0/1/2对应的ASK码作为依据
  • 注意OLED相关函数输出的进制数

3、利用python作为串口助手进行收发

芜湖!!任务二也完成辣!是不是很开心呢┗( ▔, ▔ )┛

接下来登场的是手势识别数字,期待与你的再次相遇!

特别声明:以上的图片部分来自于网络,感谢CSDN、知乎等平台上各位博主的分享,本文用作交流学习予以引用,在此一并表示感谢!

  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
STM32和迪文串口屏是两个常用的电子元器件,在实际应用中它们通常需要进行通信。本篇文章将简要介绍如何通过串口通信控制STM32来实现点灯和温度显示的功能。 首先,我们需要了解一下串口通信的相关知识。串口通信是一种数据传输方式,在单片机中通常使用USART或UART模块实现。串口通信的特点是传输速率比较慢,但可靠性较高。串口通信需要发送和接收两个端口分别连接到发送和接收设备上。 在使用STM32和迪文串口屏进行通信之前,我们需要先准备好相关的硬件设备和软件环境。硬件方面,我们需要一块基于STM32的开发板和一块迪文串口屏。软件方面,我们需要安装Keil MDK软件和相应的程序库,并进行相应的程序编写和调试。 具体实现的步骤如下: 1、在Keil MDK中创建工程,并添加相应的程序库和头文件。 2、编写程序代码,实现串口通信功能,包括串口初始化、发送和接收数据等操作。 3、连接迪文串口屏,通过串口发送相应的命令,控制迪文串口屏进行相应的操作,如点灯和温度显示等。 4、调试程序,并进行相应的优化和改进。 通过以上步骤,就可以实现STM32与迪文串口屏的通信,从而实现点灯和温度显示的功能。需要注意的是,在实际应用中,需要根据具体的需求对通信协议进行相应的设计和实现。同时,由于串口通信有一定的延迟和传输误差,需要进行相应的优化和调试,以保证通信的稳定性和可靠性。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值