六、STM32F429IGT6 串口通讯

一、串口通讯协议

1. 串口通讯数据包的构成

在这里插入图片描述

  • 起始位:必须由一个逻辑0的数据位表示
  • 有效数据:起始位之后紧接着的就是要传输的主体数据内容,也称有效数据,有效数据的长度常被约定为5、6、7或8位长。
  • 校验位:在有效数据之后,有一个可选的数据校验位。校验方法有奇校验(odd)、偶校验
    (even)、0 校验 (space)、1 校验 (mark) 及无校验(noparity)。
奇校验(odd)有效数据与校验位中“1”的个数总和为奇数
偶校验(even)有效数据与校验位中“1”的个数总和为偶数
0 校验 (space)无论有效数据中的内容是什么,校验位总为“0”
1 校验 (mark) 无论有效数据中的内容是什么,校验位总为“1”
无校验(noparity) 数据包中不包含校验位
  • 停止位:由0.5、1、1.5或2个逻辑1的数据位表示

二、STM32 USART

  • STM32芯片具有多个USART外设用于串口通讯
  • USART是UniversalSynchronousAsynchronousReceiver and Transmitter 的缩写,即通用同步异步收发器可以灵活地与外部设备进行全双工数据交换。
  • STM32芯片还有具有UART外设(Universal Asynchronous Receiver and Transmitter),它是在USART 基础上裁剪掉了同步通信功能,只有异步通信。
1. 引脚介绍

在这里插入图片描述

  • TX:发送数据输出引脚
  • RX:接收数据输入引脚
  • SW_RX:数据接收引脚,只用于单线和智能卡模式,属于内部引脚,没有具体外部引脚
  • nRTS:请求发送,n表示低电平有效; nCTS:允许发送,n表示低电平有效。相当于一个握手的过程
  • SCLK:发送器时钟输出引脚,仅适用于同步模式

注: 以上引脚,通常仅使用TX和RX

  • STM32F429IGT6芯片的USART引脚
    在这里插入图片描述
2. 数据寄存器
  • USART 的数据寄存器 (USART_DR) 只有低9位有效,且第9位数据是否有效取决于USART
    控制寄存器1(USART_CR1)的M位设置,当M位为0时表示8位数据字长,当M位为1表示9
    位数据字长,我们一般使用8位数据字长。
  • USART_DR 用于存储已发送的数据或接收到的数据。USART_DR 实际包含两个寄存器,一个是专门用于发送的可写TDR,一个是专门用于接收的可读RDR。
  • 发送数据时,往USART_DR写入的数据会自动存储到TDR;读取数据时,从USART_DR读取数据会自动提取RDR数据。
3. 数据发送/接收流程

在这里插入图片描述

  • 字长由USART控制寄存器1(USART_CR1)的M位设置:
    在这里插入图片描述
  • 停止位由USART控制寄存器2(USART_CR2)的第12位和13位控制
    在这里插入图片描述
  • 在利用USART收发数据时,需要先使能USART,再使能发送/接收
    在这里插入图片描述
    在这里插入图片描述
  • 发送数据时,涉及的重要标志位如下:
    在这里插入图片描述
    在这里插入图片描述
  • 接收数据时,涉及的重要标志位如下:
    在这里插入图片描述
    在这里插入图片描述

三、应用

1. 目标:利用 USART1 数据发送、数据接收、接收中断功能实现自动回传上位机发来的数据
  • usart.c
#include "usart.h"


static void USART1_NVIC_Config(void);


void USART_Config(void) 
{
		GPIO_InitTypeDef  GPIO_InitStructure;
		USART_InitTypeDef USART_InitStructure;
	
		RCC_AHB1PeriphClockCmd(USART1_TX_CLK | USART1_RX_CLK, ENABLE);					   					// 使能相应 GPIO 时钟
		RCC_APB2PeriphClockCmd(USART1_CLK, ENABLE);														 	// 使能 UART1 时钟
	
		/* 1. 配置 GPIO  */
		GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;       										 		// 复用功能模式
		GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;       										 		// 推挽输出 + 上拉电阻,以确保信号稳定和电平匹配
		GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
		GPIO_InitStructure.GPIO_Speed = GPIO_Fast_Speed;     										 		// 50MHz
	
		GPIO_InitStructure.GPIO_Pin   = USART1_TX_PIN;
		GPIO_Init(USART1_TX_PORT, &GPIO_InitStructure);
	
		GPIO_InitStructure.GPIO_Pin   = USART1_RX_PIN;
		GPIO_Init(USART1_RX_PORT, &GPIO_InitStructure);
	
		/* 2. 连接 GPIOX_X 到 UARTx  */
		GPIO_PinAFConfig(USART1_TX_PORT, USART1_TX_SOURCE, USART1_TX_AF);
		GPIO_PinAFConfig(USART1_RX_PORT, USART1_RX_SOURCE, USART1_RX_AF);
		
		/* 3. 配置 USART  */
		USART_InitStructure.USART_BaudRate 						= USART1_BAUDRATE;                    // 波特率
		USART_InitStructure.USART_WordLength 					= USART_WordLength_8b;                // 字长 (数据位 + 校验位):8
		USART_InitStructure.USART_Parity  						= USART_Parity_No;                    // 无奇偶校验
		USART_InitStructure.USART_StopBits 						= USART_StopBits_1;                   // 1位停止位
		USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;               // 不使用硬件流
		USART_InitStructure.USART_Mode 							= USART_Mode_Rx | USART_Mode_Tx;      // 同时使能发送和接收
		
		USART_Init(USART1, &USART_InitStructure);
		
		/* 4. 配置 USART 中断  */
		USART1_NVIC_Config();
		
		/* 5. 使能 USART 接收中断  */
		USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); 
		
		/* 6. 使能 USART1 */
		USART_Cmd(USART1, ENABLE);
}


void USART1_NVIC_Config(void)
{
		NVIC_InitTypeDef NVIC_InitStructure;
	
		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);           						 							// 配置中断优先级分组
	 
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;							 					    // 主优先级
		NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 1;							 						// 子优先级
		NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
	
		NVIC_InitStructure.NVIC_IRQChannel                   = USART1_EXTI_IRQ; 						            // 中断通道
		NVIC_Init(&NVIC_InitStructure);
}


/**
  * @brief  通过 USART 发送 8 bit 数据
  * @param  USARTx: 发送数据的USART
  * @param  data  : 待发送的数据
  * @retval 无
  */

void Usart_SendByte(USART_TypeDef* USARTx, uint8_t data) 
{
    USART_SendData(USARTx, data);                                                       // 发送数据
		while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);                   // 等待发送数据寄存器为空
}


/**
  * @brief  通过 USART 发送 16 bit 数据
  * @param  USARTx: 发送数据的USART
  * @param  data  : 待发送的数据
  * @retval 无
  */
void Usart_SendHalfWord(USART_TypeDef* USARTx, uint16_t data)
{
	uint8_t temp_h, temp_l;
	
	temp_h = (data & 0XFF00)>>8;                                                          // 取出高八位
	
	temp_l = data & 0XFF;                                                                 // 取出低八位 
	
	USART_SendData(USARTx,temp_h);	                                                      // 发送高八位
	while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
	
	USART_SendData(USARTx,temp_l);	                                                      // 发送低八位
	while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);	
}


/**
  * @brief  通过 USART 发送字符串
  * @param  USARTx: 发送数据的USART
  * @param  *str  : 待发送的字符串
  * @retval 无
  */
void Usart_SendString(USART_TypeDef * USARTx, char *str)
{
	unsigned int k=0;
	
  do 
  {
      Usart_SendByte(USARTx, *(str + k) );
      k++;
  } while( *(str + k) != '\0' );
  
  while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)==RESET);
}
  • usart.h
#ifndef __UART_H
#define __UART_H

#include "stm32f4xx.h"

#define USART1_BAUDRATE         115200                     // UART1波特率
#define USART1_CLK              RCC_APB2Periph_USART1
#define USART1_EXTI_IRQ         USART1_IRQn
#define USART1_IRQHandler       USART1_IRQHandler


#define USART1_TX_CLK           RCC_AHB1Periph_GPIOA
#define USART1_TX_PORT          GPIOA
#define USART1_TX_PIN           GPIO_Pin_9
#define USART1_TX_SOURCE		GPIO_PinSource9
#define USART1_TX_AF            GPIO_AF_USART1


#define USART1_RX_CLK           RCC_AHB1Periph_GPIOA
#define USART1_RX_PORT          GPIOA
#define USART1_RX_PIN           GPIO_Pin_10
#define USART1_RX_SOURCE		GPIO_PinSource10
#define USART1_RX_AF            GPIO_AF_USART1


void USART_Config(void); 
void Usart_SendByte(USART_TypeDef* USARTx, uint8_t data);
void Usart_SendHalfWord(USART_TypeDef* USARTx, uint16_t data);
void Usart_SendString(USART_TypeDef * USARTx, char *str);


#endif

  • 在stm32f4xx_it.c文件中添加如下代码
#include "usart.h"

/* USART1 数据接收中断 */
void USART1_IRQHandler(void)
{
		uint8_t ucTemp;
		if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
		{		
			ucTemp = USART_ReceiveData(USART1);
			USART_SendData(USART1, ucTemp);    
		}			
}
  • main.c
#include "stm32f4xx.h"
#include "usart.h"

int main(void) 
{
		USART_Config();
		while(1)
		{
		}
}
  • 编译运行即可
2. 目标:使USART1支持 printf 和 scanf

在这里插入图片描述

  • 在 usart.h 中添加如下代码
#include <stdio.h>
  • 在 usart.c 中添加如下代码
/**
  * @brief  重定向c库函数printf到串口,重定向后可使用printf函数
  */
int fputc(int ch, FILE *f)
{
		USART_SendData(USART1, (uint8_t) ch);
		while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);		
	
		return (ch);
}

/**
  * @brief  重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
  */
int fgetc(FILE *f)
{
		while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);                      // 等待串口输入数据

		return (int)USART_ReceiveData(USART1);
}
  • 在main.c中进行测试
    注:测试该功能时,为保证系统稳定性,需要将接收中断失能。将usart.c文件中USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); 的第三个参数设置为DISABLE即可。
#include "stm32f4xx.h"
#include "usart.h"

int main(void) 
{
		char ch;	
		USART_Config();
		
		while(1)
		{
			ch = getchar();
			printf("接收到字符:%c\n", ch);
		}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值