/***************************************************************************
* @file bsp_serial1.c
* Created on: 2025-03-18
* Author: YL Monitor Software group
****************************************************************************/
#include "main.h"
/************************ Private macros *************************/
#if SERIAL1_DMATx_ENABLE //开启串行通信1 DMA 发送中断 -- 1
/* 串行通信 DMA发送缓冲区大小 */
#define SERIAL_TX_BUFF_SIZE 400
#endif
#if SERIAL1_DMARx_ENABLE //开启串行通信1 DMA 接收中断
/* 串行通信 DMA接收缓冲区大小 */
#define SERIAL_RX_BUFF_SIZE 400
#endif
/************************ Private variables *************************/
#if SERIAL1_DMATx_ENABLE //开启串行通信1 DMA 发送中断 -- 1
/* 串行通信 DMA发送缓存 */
static uint8_t DMA_TxBuff[SERIAL_TX_BUFF_SIZE];
#endif
#if SERIAL1_DMARx_ENABLE //开启串行通信1 DMA 接收中断
/* 串行通信 DMA接收缓存 */
static uint8_t DMA_RxBuff[SERIAL_RX_BUFF_SIZE];
#endif
/* 串行通信 接收数据队列 */
static QueueHandle_t queueRecvData = NULL;
static SemaphoreHandle_t mutexSerialSend = NULL;
/* 串行通信2 数据接收离线状态时间计数器
* 在硬件定时器中进行累加
* DMA接收中断中清零
* 当离线超过5ms,接收结束,或者设备离线,可以进行数据转发至上位机*/
static uint16_t recv_offline_timer_count = 0;
/****************************************
* @funName : BSP_HwInitSerial1
* @Description : 串行通信口1 硬件资源初始化
* @Athor : YL Software Group
* @Version : V0.0.0
* @Data : 2025/3/22
********************************************/
void BSP_HwInitSerial1(void)
{
GPIO_InitTypeDef GPIO_InitStructure ={0};
USART_InitTypeDef USART_InitStructure ={0};
NVIC_InitTypeDef NVIC_InitStructure ={0};
DMA_InitTypeDef DMA_InitStructure ={0};
/****************Tx****************/
GPIO_InitStructure.GPIO_Pin = SERIAL1_TX_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
//GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//-----------
GPIO_Init(SERIAL1_TX_PORT, &GPIO_InitStructure);
/****************Rx****************/
GPIO_InitStructure.GPIO_Pin = SERIAL1_RX_PIN;
//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入---------
GPIO_Init(SERIAL1_RX_PORT, &GPIO_InitStructure);
/* 串行通信初始化 */
USART_DeInit(SERIAL1);
USART_InitStructure.USART_BaudRate = SERIAL1_BAUD_RATE; //波特率
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(SERIAL1, &USART_InitStructure);
#if SERIAL1_IT_ENABLE //开启串行通信1中断
NVIC_InitStructure.NVIC_IRQChannel = SERIAL1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = SERIAL1_PreemptionPriority;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
#endif
#if SERIAL1_DMATx_ENABLE //开启串行通信1 DMA 发送中断
/* DMA发送初始化 */
DMA_DeInit(SERIAL1_DMATx_Channel);
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&SERIAL1->DR);
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)DMA_TxBuff;//(uint32_t)(USART3.pbRx) 目标BUF 既是要写在哪个数组中
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = SERIAL_TX_BUFF_SIZE;//DMA缓存的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址寄存器不递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//内存字节为单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//内存字节为单位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //DMA_Mode_Circular DMA_Mode_Normal-工作在正常缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High;//4优先级之一的(高优先级)
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//非内存到内存
DMA_Init(SERIAL1_DMATx_Channel, &DMA_InitStructure);
/* DMA发送中断优先级设置 */
NVIC_InitStructure.NVIC_IRQChannel = SERIAL1_DMATx_IRQn ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = SERIAL1_DMATx_PreemptionPriority;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_ITConfig(SERIAL1_DMATx_Channel, DMA_IT_TC, ENABLE);//使能DMA1传输完成中
DMA_Cmd(SERIAL1_DMATx_Channel, ENABLE);//启用DMA1通道
#endif
#if SERIAL1_DMARx_ENABLE //开启串行通信1 DMA 接收中断
/* DMA接收初始化 */
DMA_DeInit(SERIAL1_DMARx_Channel);
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&SERIAL1->DR);//源头是BUF既是(&(SERIAL1->DR))
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)DMA_RxBuff; //(uint32_t)(USART3.pbRx) 目标BUF 既是要写在哪个数组中
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//外设做源头-外设是作为数据传输的目的地还是来源
DMA_InitStructure.DMA_BufferSize = SERIAL_RX_BUFF_SIZE;//DMA缓存的大小! 单位在下边设定
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址寄存器不递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设字节为单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//内存字节为单位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //循环模式DMA_Mode_Circular DMA_Mode_Normal-工作在正常缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High;//DMA_Priority_VeryHigh,DMA_Priority_High,DMA_Priority_Medium(初始使用); ----------------
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//非内存到内存
DMA_Init(SERIAL1_DMARx_Channel, &DMA_InitStructure);
/* DMA接收中断优先级设置 */
NVIC_InitStructure.NVIC_IRQChannel = SERIAL1_DMARx_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = SERIAL1_DMARx_PreemptionPriority;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//DMA_ITConfig(SERIAL1_DMARx_Channel, DMA_IT_TC, ENABLE);//开启DMA1接收输完成中-需要屏蔽
DMA_ITConfig(SERIAL1_DMARx_Channel, DMA_IT_TC, DISABLE);//禁用DMA1传输完成中
DMA_Cmd(SERIAL1_DMARx_Channel, ENABLE);
#endif
USART_DMACmd(SERIAL1, USART_DMAReq_Rx | USART_DMAReq_Tx, ENABLE);//使能USART3的DMA发送,接收请求
//USART_ITConfig(SERIAL1, USART_IT_RXNE, ENABLE);
USART_ITConfig(SERIAL1, USART_IT_IDLE, ENABLE); //启用的USART3中断
USART_Cmd(SERIAL1, ENABLE);
}
/*********************************************
* @funName : BSP_SwInitSerial1
* @Description : 串行通信口1 软件资源初始化
* @Athor : YL Software Group
* @Version : V0.0.0
* @Data : 2025/3/22
************************************************/
void BSP_SwInitSerial1(void)
{
if(NULL == queueRecvData)
{
queueRecvData = xQueueCreate(SERIAL_DATA_QUEUE_SIZE, sizeof(uint8_t));
/* 数据接收队列创建失败 */
if(NULL == queueRecvData)
{
}
}
if(NULL == mutexSerialSend)
{
mutexSerialSend = xSemaphoreCreateBinary();
/* 数据发送互斥量创建失败 */
if(NULL == mutexSerialSend)
{
}
else
{
/* 释放数据发送互斥量 */
xSemaphoreGive(mutexSerialSend);
}
}
}
/******************************************
* @funName : SERIAL1_IRQHandler
* @Description : 串行通信口1 中断,用于处理空闲接收中断,
* 获取DMA接收的数据,并缓存至数据队列
* @Athor : YL Software Group
* @Version : V0.0.0
* @Data : 2025/3/22
**************************************************/
void SERIAL1_IRQHandler(void)
{
uint8_t byte = 0;
uint16_t i = 0, rlen = 0;
//if(USART_GetITStatus(SERIAL1, USART_IT_RXNE) != RESET)//接收数据寄存器不空中断
if(USART_GetITStatus(SERIAL1, USART_IT_IDLE) != RESET)//检查UART4中断是否发生 空闲线路检测中断
{
portBASE_TYPE xRecvWoken = pdFALSE;
byte = USART_ReceiveData(SERIAL1);//返回USART3外设最近接收到的数据
if(recv_offline_timer_count > 45)
{
xQueueReset(queueRecvData);
}
recv_offline_timer_count = 0;
#if SERIAL1_DMARx_ENABLE//接收中断
rlen = SERIAL_RX_BUFF_SIZE - DMA_GetCurrDataCounter(SERIAL1_DMARx_Channel);
DMA_ClearFlag(SERIAL1_DMARx_FLAG);//清除DMA2通道的挂起标志
DMA_Cmd(SERIAL1_DMARx_Channel, DISABLE);//禁止DMA1接收
if(recv_offline_timer_count > 45)
{
xQueueReset(queueRecvData);
}
recv_offline_timer_count = 0;
if(rlen > 0 && NULL != queueRecvData)
{
/* DMA接收数据存入数据队列 */
for(i = 0; i < rlen;i ++)//i++不能写错
{
//recv_offline_timer_count = 0;
if(errQUEUE_FULL == xQueueSendFromISR(queueRecvData, &DMA_RxBuff[i], &xRecvWoken))//队列从ISR发送
{
break;
}
}
}
USART_ClearITPendingBit(SERIAL1, USART_IT_IDLE);
DMA_SetCurrDataCounter(SERIAL1_DMARx_Channel, SERIAL_RX_BUFF_SIZE);//设置当前DMA2通道3传输中的数据单元数
DMA_Cmd(SERIAL1_DMARx_Channel, ENABLE);
#else
USART_ClearITPendingBit(SERIAL1, USART_IT_RXNE);//清除USART3的中断挂起位
xQueueSendFromISR(queueRecvData, &byte, &xRecvWoken);//调用xQueueGenericSendFromISR()的宏
#endif
}
/* 全部数据发送完成,产生该标记 */
if (USART_GetITStatus(SERIAL1, USART_IT_TC) != RESET)//检查USART3中断是否发生
{
USART_ClearITPendingBit(SERIAL1, USART_IT_TC); //清除USART3的中断挂起位-传输完全中断
}
}
#if SERIAL1_DMATx_ENABLE
/*****************************************
* @funName : SERIAL1_DMATx_IRQHandler
* @Description : 串行通信口1 DMA 发送中断
* @Athor : YL Software Group
* @Version : V0.0.0
* @Data : 2025/3/24
*******************************************/
void SERIAL1_DMATx_IRQHandler(void)
{
portBASE_TYPE xSendWoken = pdFALSE;
if(RESET != DMA_GetITStatus(SERIAL1_DMATx_IT_TC))
{
/* 关闭 DMA */
DMA_Cmd(SERIAL1_DMATx_Channel, DISABLE);
/* 清除标记 */
DMA_ClearITPendingBit(SERIAL1_DMATx_IT_TC);
/* 清除数据长度 */
DMA_SetCurrDataCounter(SERIAL1_DMATx_Channel, 0);
USART_ITConfig(SERIAL1, USART_IT_TC, DISABLE);
if(NULL != mutexSerialSend)
{
/* 释放 OS 数据发送权限 */
xSemaphoreGiveFromISR(mutexSerialSend, &xSendWoken);
portYIELD_FROM_ISR(xSendWoken);
}
}
}
#endif
/**********************************************
* @funName : BSP_Send2Serial1
* @Description : 串行通信口1 DMA发送启动
* @Athor : YL Software Group
* @Version : V0.0.0
* @Data : 2025/3/22
**********************************************/
void BSP_Send2Serial1(uint8_t* sbuf, const uint16_t slen)
{
uint16_t len = slen;
if(slen == 0||NULL == sbuf)
{
return;
}
if(len > SERIAL_TX_BUFF_SIZE)
{
len = SERIAL_TX_BUFF_SIZE;
}
/********************************************
*获取OS 数据发送权限
* <DMA发送完成后,在串行通信中断服务中释放>
*********************************************/
if(NULL != mutexSerialSend)
{
xSemaphoreTake(mutexSerialSend, portMAX_DELAY);
}
#if SERIAL1_DMATx_ENABLE
else
{
while(!DMA_GetFlagStatus(SERIAL1_DMATx_IT_TC));
}
#endif
#if SERIAL1_DMATx_ENABLE
DMA_SetCurrDataCounter(SERIAL1_DMATx_Channel, len);
/*发送DMA流的地址不自增*/
SERIAL1_DMATx_Channel->CCR |= (1 << 10);
/*设置接收和发送的内存地址*/
SERIAL1_DMATx_Channel->CMAR = (uint32_t)sbuf;
DMA_Cmd(SERIAL1_DMATx_Channel, ENABLE);
USART_DMACmd(SERIAL1, USART_DMAReq_Tx, ENABLE);
#else
{
uint16_t i = 0;
while(i < len)
{
USART_SendData(SERIAL1, sbuf[i]);
}
if(NULL != mutexSerialSend)
{
xSemaphoreGive(mutexSerialSend);
}
}
#endif
}
/********************************************
* @funName : BSP_Recv4Serial1
* @Description : 从串口1接收数据队列获取数据
* @Athor : YL Software Group
* @Version : V0.0.0
* @Data : 2025/3/22
**********************************************/
void BSP_Recv4Serial1(uint8_t * rbuf, uint16_t* rlen)
{
int iCnt = 0, len;
*rlen = 0;
if(NULL == queueRecvData || NULL == rbuf)
{
return;
}
len = uxQueueMessagesWaiting(queueRecvData);//排队等待消息
for(iCnt = 0; iCnt < len; ++iCnt)
{
if(pdFALSE == xQueueReceive(queueRecvData, &rbuf[iCnt], 0))
{
break;
}
}
*rlen = iCnt;
}
/*********************************************
* @funName : BSP_GetCurRecv4Serial1
* @Description : 获取串口1接收数据队列当前数据长度
* @Athor : YL Software Group
* @Version : V0.0.0
* @Data : 2025/4/03
*************************************************/
uint16_t BSP_GetCurRecv4Serial1(void)
{
//等待中的消息队列(通信 接收数据队列)
return uxQueueMessagesWaiting(queueRecvData);
}
/****************************************
* @funName : BSP_SetRecvOffline4Serial1
* @Description : 对数据监听离线状态时间计数进行更新(硬件定时器中执行)
* @Athor : YL Software Group
* @Version : V0.0.0
* @Data : 2025/4/02
********************************************/
void BSP_SetRecvOffline4Serial1(void)
{
++recv_offline_timer_count;
}
/**********************************************
* @funName : BSP_GetRecvOffline4Serial1
* @Output : 离线状态时间计数
* @Description : 读取数据监听离线状态时间计数(硬件定时器中执行)
* @Athor : YL Software Group
* @Version : V0.0.0
* @Data : 2025/4/02
*********************************************/
uint16_t BSP_GetRecvOffline4Serial1(void)
{
return recv_offline_timer_count;
}
/************************ End of file *************************/
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART3->SR&0X40)==0);//循环发送,直到发送完毕
USART1->DR = (u8) ch;
return ch;
}
以上代码不用FreeRTOS的队列形式实现数据接收功能,用标准库写出详细代码,并加上注释
最新发布