Files

297 lines
16 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "USART.h"
/**
* @brief 串口1的初始化函数
* @note 使用USART1串口PA9->USART1_RXPA10->USART1_TX波特率设置为115200。
* @param *xUsartId 选择串口号
* @param ulBaudrate 要设置的波特率
* @retval None
*/
void vUsartInit(USART_TypeDef *xUsartId, uint32_t ulBaudrate)
{
if (xUsartId == USART1)
{
/* code */
RCC_APB2PeriphClockCmd(USART1_GPIO_CLOCK, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = USART1_GPIO_PIN_TX;
GPIO_Init(USART1_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = USART1_GPIO_PIN_RX;
GPIO_Init(USART1_GPIO_PORT, &GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = ulBaudrate; // 设定后USART_Init函数内部会自动算好9600对应的分频系数并写到BRR寄存器
RCC_APB1PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 硬件流控制,不使用流控
USART_InitStructure.USART_Mode = USART_Mode_Tx|USART_Mode_Rx; // 串口模式,如果既使用输入和输出模式就用或符号,发送模式和接收模式
USART_InitStructure.USART_Parity = USART_Parity_No; // 无校验位
USART_InitStructure.USART_StopBits = USART_StopBits_1; // 一位停止位
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字长不需要校验字长就选择8位
USART_Init(USART1,&USART_InitStructure);
// 上面是串口的查询模式如果使用中断还需要开启中断配置NVIC
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 选择RXNE的中断,并开启RXNE标志位到NVIC的输出如果RXNE标志位置1就会向NVIC申请中断之后可以在中断函数中接收数据
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); // 分组分组4为4bit抢占优先级和0bit响应优先级抢占优先级可设置为0-15。由于FreeRTOS没有响应优先级而优先级分组4相当于4位抢占优先级和0位响应优先级。
NVIC_InitTypeDef NVIC_InitStructure; // 初始化NVIC的USART1通道
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; // 中断通道
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 7; // 抢占优先级配置根据FreeRTOS设置配置在范围内可以调用FreeRTOS的以“FromISR()”结尾的api函数。
// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 响应优先级配置,用不上了
NVIC_Init(&NVIC_InitStructure); // 指向NVIC_InitStructure的地址
USART_Cmd(USART1,ENABLE);
} else if (xUsartId == USART2)
{
/* code */
RCC_APB2PeriphClockCmd(USART2_GPIO_CLOCK,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = USART2_GPIO_PIN_TX;
GPIO_Init(USART2_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = USART2_GPIO_PIN_RX;
GPIO_Init(USART2_GPIO_PORT, &GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = ulBaudrate; // 设定后USART_Init函数内部会自动算好9600对应的分频系数并写到BRR寄存器
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 硬件流控制,不使用流控
USART_InitStructure.USART_Mode = USART_Mode_Tx|USART_Mode_Rx; // 串口模式,如果既使用输入和输出模式就用或符号,发送模式和接收模式
USART_InitStructure.USART_Parity = USART_Parity_No; // 无校验位
USART_InitStructure.USART_StopBits = USART_StopBits_1; // 一位停止位
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字长不需要校验字长就选择8位
USART_Init(USART2, &USART_InitStructure);
// 上面是串口的查询模式如果使用中断还需要开启中断配置NVIC
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); // 选择RXNE的中断,并开启RXNE标志位到NVIC的输出如果RXNE标志位置1就会向NVIC申请中断之后可以在中断函数中接收数据
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); // 分组分组4为4bit抢占优先级和0bit响应优先级抢占优先级可设置为0-15。由于FreeRTOS没有响应优先级而优先级分组4相当于4位抢占优先级和0位响应优先级。
NVIC_InitTypeDef NVIC_InitStructure; // 初始化NVIC的USART1通道
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; // 中断通道
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5; // 抢占优先级配置根据FreeRTOS设置配置在范围内可以调用FreeRTOS的以“FromISR()”结尾的api函数。
// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 响应优先级配置,用不上了
NVIC_Init(&NVIC_InitStructure); // 指向NVIC_InitStructure的地址
USART_Cmd(USART2, ENABLE);
} else if (xUsartId == USART3)
{
/* code */
RCC_APB2PeriphClockCmd(USART3_GPIO_CLOCK,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = USART3_GPIO_PIN_TX;
GPIO_Init(USART3_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = USART3_GPIO_PIN_RX;
GPIO_Init(USART3_GPIO_PORT, &GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = ulBaudrate; // 设定后USART_Init函数内部会自动算好9600对应的分频系数并写到BRR寄存器
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 硬件流控制,不使用流控
USART_InitStructure.USART_Mode = USART_Mode_Tx|USART_Mode_Rx; // 串口模式,如果既使用输入和输出模式就用或符号,发送模式和接收模式
USART_InitStructure.USART_Parity = USART_Parity_No; // 无校验位
USART_InitStructure.USART_StopBits = USART_StopBits_1; // 一位停止位
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字长不需要校验字长就选择8位
USART_Init(USART3,&USART_InitStructure);
// 上面是串口的查询模式如果使用中断还需要开启中断配置NVIC
USART_ITConfig(USART3,USART_IT_RXNE,ENABLE); // 选择RXNE的中断,并开启RXNE标志位到NVIC的输出如果RXNE标志位置1就会向NVIC申请中断之后可以在中断函数中接收数据
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); // 分组分组4为4bit抢占优先级和0bit响应优先级抢占优先级可设置为0-15。由于FreeRTOS没有响应优先级而优先级分组4相当于4位抢占优先级和0位响应优先级。
NVIC_InitTypeDef NVIC_InitStructure; // 初始化NVIC的USART1通道
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn; // 中断通道
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 6; // 抢占优先级配置根据FreeRTOS设置配置在范围内可以调用FreeRTOS的以“FromISR()”结尾的api函数。
// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 响应优先级配置,用不上了
NVIC_Init(&NVIC_InitStructure); // 指向NVIC_InitStructure的地址
USART_Cmd(USART3, ENABLE);
}
}
/**
* @brief 串口发送单个字节函数
* @note 调用这个函数就可以从TX引脚发送一个字节数据。
* @param *xUsartId 选择串口号
* @param ucByte 要发送的字节
* @retval None
*/
void vUsartSendByte(USART_TypeDef *xUsartId, uint8_t ucByte)
{
USART_SendData(xUsartId, ucByte); // 调用这个函数Byte就写入TDR寄存器了
// 写完之后还需要等待一下等TDR的数据转移到移位寄存器就可以了如果数据还在TDR寄存器中再写入数据就会产生数据覆盖所以在发送之后还需要等待一下标志位
while(USART_GetFlagStatus(xUsartId, USART_FLAG_TXE) == RESET); // 发送数据寄存器空标志位等待TXE置1所以需要套一个while循环 TXE:发送数据寄存器空发送完标志位自动置0不用手动复位。
}
/**
* @brief 串口发送数组函数
* @note 一般用于16进制模式下。uint8_t的指针类型指向待发送数组的首地址,由于数组无法判断是否结束所以需要再传递一个Length进来。
* @param *xUsartId 选择串口号
* @param *pucArray 要发送的十六进制数字
* @param usLength 发送长度
* @retval None
*/
void vUsartSendArray(USART_TypeDef *xUsartId, uint8_t *pucArray, uint16_t usLength)
{
for(uint16_t i = 0; i < usLength; i ++) // for循环执行Length次可以对Array数据进行遍历实际定义数组不要超出uint16_t的范围即可
{
vUsartSendByte(xUsartId, pucArray[i]); // 依次取出数组Array的每一项
}
}
/**
* @brief 串口发送字符串函数
* @note 将字符串封装成指针数组的形式,定义数组长度直到检测到字符串的末尾结束,并将字符串根据长度拆成带个字符发送。
* @param *xUsartId 选择串口号
* @param *pcString 要发送的数据
* @retval None
*/
void vUsartSendString(USART_TypeDef *xUsartId, char *pcString) // 给uint8_t *也可以,由于字符串自带一个标志位,所以就不需要再传递长度参数了
{
for(uint8_t i = 0; pcString[i] != '\0'; i++) // 循环结束就可以用标志位来判断了,填'\0'是空字符的转义字符表示形式和直接写0是一样的
{
vUsartSendByte(xUsartId, pcString[i]); // 将String字符串一个个取出来通过SendByte发送
}
}
/**
* @brief 串口打印函数
* @note 将字符串封装成指针数组的形式,定义数组长度直到检测到字符串的末尾结束,并将字符串根据长度拆成带个字符发送。
* @param *xUsartId 选择串口号
* @param *format 字符串
* @param ... 可变参数列表
* @retval None
*/
void vUsartPrintf(USART_TypeDef *xUsartId, char *format, ...)
{
char cBuffer[100];
va_list arg; // arg是定义一个参数列表变量
va_start(arg, format); // 从format位置开始接收参数表放在arg里面
vsprintf(cBuffer, format, arg); // 封装格式要用vsprintf因为sprintf只能接收直接写的参数打印字符串格式是format参数表是arg
va_end(arg); // 释放参数表
char *p = cBuffer;
if (xUsartId == USART1)
{
/* code */
while (*p)
{
/* code */
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); // 等待发送缓冲区为空
USART_SendData(USART1, *p++);
}
} else if (xUsartId == USART2)
{
/* code */
while (*p)
{
/* code */
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
USART_SendData(USART2, *p++);
}
} else if (xUsartId == USART3)
{
/* code */
while (*p)
{
/* code */
while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
USART_SendData(USART3, *p++);
}
}
}
/**
* @brief 串口1接收中断处理函数
* @note 接收串口中断发送的每帧数据到串口消息队列中,以便后续处理数据。
* @param None
* @retval None
*/
void USART1_IRQHandler(void)
{
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
/* code */
uint8_t ulRxData = (uint8_t)USART_ReceiveData(USART1);
#if (USE_RTOS == NONE)
#elif (USE_RTOS == FREERTOS)
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xQueueSendFromISR(xQueueUsart1IrqHdlr, &ulRxData, &xHigherPriorityTaskWoken);
/* 问题根源:请求上下文切换 */
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
#elif (USE_RTOS == OSAL)
#endif
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
/**
* @brief 串口2接收中断处理函数
* @note 接收串口中断发送的每帧数据到串口消息队列中,以便后续处理数据。
* @param None
* @retval None
*/
void USART2_IRQHandler(void)
{
if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
{
/* code */
uint8_t ulRxData = (uint8_t)USART_ReceiveData(USART2);
#if (USE_RTOS == NONE)
#elif (USE_RTOS == FREERTOS)
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// xQueueSendFromISR(xQueueUsart2IrqHdlr, &ulRxData, &xHigherPriorityTaskWoken);
// if (xQueueSendFromISR(xQueueUsart2IrqHdlr, &ulRxData, &xHigherPriorityTaskWoken) != pdTRUE)
// {
// /* code */
// vUsartSendString(USART3, "Queue Init Failed!");
// }
// 添加队列状态检查
if(xQueueUsart2IrqHdlr != NULL) {
if (xQueueSendFromISR(xQueueUsart2IrqHdlr, &ulRxData, &xHigherPriorityTaskWoken) != pdTRUE) {
// 队列发送失败处理
vUsartSendString(USART3, "Queue Full or Error!");
}
} else {
vUsartSendString(USART3, "Queue Not Initialized!");
}
/* 问题根源:请求上下文切换 */
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
#elif (USE_RTOS == OSAL)
#endif
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
}
}
/**
* @brief 串口3接收中断处理函数
* @note 接收串口中断发送的每帧数据到串口消息队列中,以便后续处理数据。
* @param None
* @retval None
*/
void USART3_IRQHandler(void)
{
if (USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
{
/* code */
uint8_t ulRxData = (uint8_t)USART_ReceiveData(USART3);
#if (USE_RTOS == NONE)
#elif (USE_RTOS == FREERTOS)
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xQueueSendFromISR(xQueueUsart3IrqHdlr, &ulRxData, &xHigherPriorityTaskWoken);
/* 问题根源:请求上下文切换 */
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
#elif (USE_RTOS == OSAL)
#endif
USART_ClearITPendingBit(USART3, USART_IT_RXNE);
}
}