目录
前言
因本人备赛蓝桥杯嵌入式省赛,故编写此学习笔记进行学习上的记录。
上文我们实现了LCD程序设计,本文我们进行异步的串口通信的程序设计。
1. 串行通信介绍
串行通信又叫做串行口通信,它又分为同步通信和异步通信两种方式
1.1 同步通信
同步通信时要建立发送方时钟对接收方时钟的直接控制,是双方达到完全同步。此时,传输数据的位之间的距离均为"位间隔"的整数倍,同时传送的字符间不留间隙,即保持位同步关系,也保持字符同步关系。发送方对接收方的同步可以是外同步也可以是自同步。通俗的来说,就是以一串字符为一个传送单位,字符间不加标识位,在一串字符开始用同步字符表示,硬件要求高,通信双方必须严格同步。
1.2 异步通信
异步通信是指通信的发送与接收设备使用各自的时钟控制数据的发送和接收过程。为使双方的收发协调,要求发送和接收设备的时钟尽可能一致。以字符(构成的帧)为单位进行传输。发送方可以在任意时刻发送数据,所以用起始位和停止位标识每个字符的开始和结束,数据位从低到高传送。
2. 电路原理
通过查看查阅CT117E-M4产品手册的电路原理图可知,本开发板的PA9引脚为Tx,PA10引脚为Rx。
2. 使用CubeMX进行源工程的配置
我们在Pinout view的芯片引脚布局中将PA9设定为USART1_RX,PA10设定为USART1_Tx。
在Pinout&Configuration的Connectivity目录中选定USART1,将Mode选为Asynchronous,也就是异步模式,接下来在Parameter Setting设定需要的波特率、数字位等,我这里设定了波特率为9600,数字位为8为,无奇偶校验,一个停止位 。
将NVIC Interrupt Table中的中断使能打开,这是为了接收读取到的串口数据,当数据到来时,就进入我们编写的中断函数中。
在System Core目录的NVIC将USART1的中断优先级修改为1。
3. 代码编程
3.1 预备工作
接下来我们分别在Test工程里创建Test\Test_Project\Src\BSP\KEY\bsp_uart.c和Test\Test_Project\Inc\BSP\KEY\bsp_uart.h文件,这就是我们后面要编写的中间层代码文件。打开Test_Project工程,进行文件Group的添加。
在bsp_uart.c中添加依赖
#include "UART\bsp_uart.h"
编译后可以看到在BSP文件夹下的效果。
在stm32g4xx_hal_conf.h中修改嘀嗒定时器的优先级为0
3.2 uart.c和uart.h编写
下面我们将Source工程生成的usart.c和usart.h的代码选择性的粘贴到我们构建的模块程序中,粘贴修改后的uart.c和uart.h 如下。
uart.h
#include "main.h"
extern UART_HandleTypeDef huart1;
void UART_Init(void);
uart.c
#include "UART\bsp_uart.h"
UART_HandleTypeDef huart1;
void UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 9600;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&huart1) != HAL_OK)
{
Error_Handler();
}
}
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(uartHandle->Instance==USART1)
{
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_NVIC_SetPriority(USART1_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}
}
void UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{
if(uartHandle->Instance==USART1)
{
__HAL_RCC_USART1_CLK_DISABLE();
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);
HAL_NVIC_DisableIRQ(USART1_IRQn);
}
}
接下来我们进行代码编译,我们可以看到很多的报错,根据错误提示,应该是uart的相关依赖文件没有添加到工程,我们下来进行添加。
进行文件Group的添加,添加stm32g4xx_hal_uart.c和stm32g4xx_hal_uart_ex.c。
进入stm32g4xx_hal_conf.h这个头文件,找到HAL_UART_MODULE_ENABLED宏定义,将注释取消掉。
再进行编译,发现没有error了!
3.3 终断文件的编写
我们将Source工程中生成的stm32g4xx_it.c中的中断部分粘贴到Test_Project工程中的stm32g4xx_it.c
void SysTick_Handler(void)
{
HAL_IncTick();
}
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1);
}
3.4 main.c编写
接下来我们编写main.c函数,主要去测试一下串口的收发,就设定一个简单的功能需求:
每个1s钟发送一次"Hello World\r\n",
接收到串口数据时将led灯点亮。
3.4.1 系统时钟函数配置
系统时钟函数SystemClock_Config添加uart部分的配置
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
3.4.2 头文件引用
#include "UART\bsp_uart.h"
3.4.3 变量声明
//变量声明
__IO uint32_t uwTick_Uart_Set_Point;//Uart减速
//Uart专用变量
char str[40];
uint8_t rx_buffer;
3.4.4 函数声明
//***子函数声明区
void Uart_Proc(void);
3.4.5 函数定义
其中,HAL_UART_Transmit函数的第一个参数为串口结构体指针,第二个参数为字符串地址,第三个参数为字符串长度,第四个参数为超时时间。
void Uart_Proc(void)
{
if((uwTick - uwTick_Uart_Set_Point)<1000)return;//减速处理
uwTick_Uart_Set_Point = uwTick;
sprintf(str,"Hello World\r\n");
HAL_UART_Transmit(&huart1,(unsigned char*)str,strlen(str),50);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
LED_Disp(0xFF);
HAL_Delay(300);
LED_Disp(0x00);
HAL_UART_Receive_IT(&huart1, &rx_buffer, 1);
}
3.4.6 主要main函数部分
int main(void)
{
HAL_Init();
SystemClock_Config();
LED_Init();
UART1_Init();
//*串口接收中断打开
HAL_UART_Receive_IT(&huart1,&rx_buffer,1);
while (1)
{
Led_Proc();
Uart_Proc();
}
}
4. 测试
打开串口助手,可以看到每隔1s中
接收到Hello World字符串。
使用串口助手发送任意字符,开发板的所有灯点亮后熄灭
5. 总结
综上,本次进行了异步串口通信的编程,通过CubeMx进行PA9、PA10引脚的配置,并通过Keil5进行相关代码的编写,在最后成功测试了串口的收、发的基本功能块。