目录
一、STM32CubeMX开发
1.1 新建工程
1.2?配置 USART1
1.3?配置串口参数
1.4 设置DMA
1.5 添加串口中断
1.6 生成源代码。
二、代码部分
2.1? 接收中断处理
2.1.1 接收固定长度:(舍弃)
2.1.2?编写空闲中断函数接收不定长
?三、使用ringbuffer实现任意数据类型的FIFO处理接收数据
① fifo头文件:
②?fifo.c程序主体
③?串口初始化
④ 接收空闲中断
⑤ 主函数调用:
一、STM32CubeMX开发
1.1 新建工程
file -> new project?
选择芯片-> stm32 core内核? ? ? ? ?
? ? ? ? ? ? ? ? ? ?stm32 series 系列
? ? ? ? ? ? ? ? ? ?stm32? line
? ? ? ? ? ? ? ? ? ?stm32? package
选择芯片根据自身需求去选择,目前该项目是stm32f0系列
? ? ? ? ? ? ? ? ? ? stm32 core内核? ? ? ? ?M0
? ? ? ? ? ? ? ? ? ?stm32 series 系列? ? ? F0
? ? ? ? ? ? ? ? ? ?stm32? line? ? ? ? ? ? ? ? ?F0X1
? ? ? ? ? ? ? ? ? ?stm32? package? ? ? ? ?TSSOP 20
?1.2?配置 USART1
配置 USART1 的模式为 Asynchronous,即异步串口模式
1.3?配置串口参数
?根据需要设置波特率和数据宽度等参数,在此使用?9600,8,N,1
?1.4 设置DMA
?1.5 添加串口中断
?1.6 生成源代码。
在界面中输入工程名,保存路径,工程 IDE 类型,点 GENERATE CODE?即可。
生成代码完成后可选择打开工程。?
?
二、代码部分
对于芯片的 外设,最好的办法就是去官方查看官方发布的参考例子:
官方关于STM32CubeF0的例子:https://github.com/STMicroelectronics/STM32CubeF0
2.1? 接收中断处理
2.1.1 接收固定长度:(舍弃)
只有接收缓存到固定长度才会触发中断
串口接收回调函数
uint8_t aRxBuffer[RXBUFFERSIZE];
/* Size of Reception buffer */
#define RXBUFFERSIZE 10
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
/* Set transmission flag: trasfer complete*/
UartrxReady = SET;
HAL_UART_Transmit(&huart1, aRxBuffer, 10, 0x200);
HAL_UART_Receive_DMA(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE);
HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer,1);
}
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1);
}
static void MX_USART1_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.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if(HAL_UART_DeInit(&huart1) != HAL_OK)
{
Error_Handler();
}
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
UartrxReady=RESET;
/* USER CODE BEGIN USART1_Init 2 */
if(HAL_UART_Receive_DMA(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)
{
Error_Handler();
}
/* USER CODE END USART1_Init 2 */
}
从串口调试助手可以看只有接收的长度?RXBUFFERSIZE为10时,才触发接收回调函数。
2.1.2?编写空闲中断函数接收不定长
USART1初始化:
static void MX_USART1_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.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if(HAL_UART_DeInit(&huart1) != HAL_OK)
{
Error_Handler();
}
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
/* USER CODE BEGIN USART1_Init 2 */
if(HAL_UART_Receive_DMA(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)
{
Error_Handler();
}
}
空闲中断函数:?
#define TXBUFFERSIZE 30
/* Size of Reception buffer */
#define RXBUFFERSIZE 30
void USAR_UART_IDLECallback(UART_HandleTypeDef *huart)
{
HAL_UART_DMAStop(&huart1);
uint8_t data_length = RXBUFFERSIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
HAL_UART_Transmit(&huart1,aRxBuffer,data_length,0x200);
memset(aRxBuffer,0x00,data_length);
data_length = 0;
HAL_UART_Receive_DMA(&huart1, (uint8_t*)aRxBuffer, RXBUFFERSIZE);
}
void USER_UART_IRQHandler(UART_HandleTypeDef *huart)
{
if(USART1 == huart1.Instance)
{
if(RESET != __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
USAR_UART_IDLECallback(huart);
}
}
}
/**
* @brief This function handles USART1 global interrupt / USART1 wake-up interrupt through EXTI line 25.
*/
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1);
USER_UART_IRQHandler(&huart1);
}
可实现不定长的接收!?
?注意:
在中断中,尽量处理简单,不要做过多的处理,如发射,可以在函数外执行。
?三、使用ringbuffer实现任意数据类型的FIFO处理接收数据
使用原因:
????????虽然将数据保存在DMA接收缓存中,但在处理接收数据时,可能存在接收新的数据在调用数据完覆盖了接收缓存,导致调用数据时候会出现与原计划的处理不同的问题。
? ? ? ? 因此,使用ringbuffer将DMA接收缓存,以防数据的被覆盖
参考:https://blog.csdn.net/xmxqiyan/article/details/43408291?utm_source=itdadao&utm_medium=referral?
① fifo头文件:
#ifndef __FIFO_H_
#define __FIFO_H_
#pragma pack(4)
typedef struct FIFO_Type_STRU
{
unsigned int Depth; // Fifo深度
volatile unsigned int Head; // Head为起始元素
volatile unsigned int Tail; // Tail-1为最后一个元素
volatile unsigned int Counter; // 元素个数
unsigned int ElementBytes; // 每个元素的字节数element
void *Buff; // 缓存区
}FIFO_Type;
#pragma pack()
/********************************************************************//**
* @brief FIFO初始化
* @param[in] pFIFO: FIFO指针
* @param[in] pBuff: FIFO中缓存
* @param[in] elementBytes:FIFO每个元素的字节数
* @param[in] depth: FIFO深度
* @return None
*********************************************************************/
void FIFO_Init(FIFO_Type *pFIFO, void *pBuff, unsigned int elementBytes, unsigned int depth);
/********************************************************************//**
* @brief 向FIFO添加一个元素
* @param[in] pFIFO: FIFO指针
* @param[in] pValue: 要添加的元素
* @return 1-TRUE or 0-FALSE
*********************************************************************/
unsigned char FIFO_AddOne(FIFO_Type *pFIFO, void *pValue);
/********************************************************************//**
* @brief 向FIFO添加多个元素
* @param[in] pFIFO: FIFO指针
* @param[in] pValues: 要添加的元素指针
* @param[in] bytesToAdd: 要添加元素的长度
* @return 实际添加的元素个数
*********************************************************************/
unsigned int FIFO_Add(FIFO_Type *pFIFO, void *pValues, unsigned int bytesToAdd);
/********************************************************************//**
* @brief 从FIFO读取一个元素
* @param[in] pFIFO: FIFO指针
* @param[in] pValue: 存放要读取的元素指针
* @return 1-TRUE or 0-FALSE
*********************************************************************/
unsigned char FIFO_GetOne(FIFO_Type *pFIFO, void *pValue);
/********************************************************************//**
* @brief 从FIFO读取多个元素
* @param[in] pFIFO: FIFO指针
* @param[out] pValues: 存放要读取的元素指针
* @param[in] bytesToRead: 要读取的元素长度
* @return 实际读取的元素个数
*********************************************************************/
unsigned int FIFO_Get(FIFO_Type *pFIFO, void *pValues, unsigned int bytesToRead);
/********************************************************************//**
* @brief 清空FIFO
* @param[in] pFIFO: FIFO指针
* @return None
*********************************************************************/
void FIFO_Clear(FIFO_Type *pFIFO);
unsigned char FIFO_IsEmpty(FIFO_Type *pFIFO);
#endif
②?fifo.c程序主体
#include <string.h>
#include "fifo.h"
/********************************************************************//**
* @brief FIFO初始化
* @param[in] pFIFO: FIFO指针
* @param[in] pBuff: FIFO中缓存
* @param[in] elementBytes:FIFO每个元素的字节数
* @param[in] depth: FIFO深度
* @return None
*********************************************************************/
void FIFO_Init(FIFO_Type *pFIFO, void *pBuff, unsigned int elementBytes, unsigned int depth)
{
pFIFO->Buff = pBuff;
pFIFO->ElementBytes = elementBytes;
pFIFO->Depth = depth;
pFIFO->Head = 0;
pFIFO->Tail = 0;
pFIFO->Counter = 0;
}
/********************************************************************//**
* @brief 判断FIFO是否为空
* @param[in] pFIFO: FIFO指针
* @return 1-TRUE or 0-FALSE
*********************************************************************/
unsigned char FIFO_IsEmpty(FIFO_Type *pFIFO)
{
return (pFIFO->Counter == 0);
}
/********************************************************************//**
* @brief 判断FIFO是否已满
* @param[in] pFIFO: FIFO指针
* @return TRUE or FALSE
*********************************************************************/
unsigned char FIFO_IsFull(FIFO_Type *pFIFO)
{
return (pFIFO->Counter == pFIFO->Depth);
}
/********************************************************************//**
* @brief 向FIFO添加一个元素
* @param[in] pFIFO: FIFO指针
* @param[in] pValue: 要添加的元素
* @return 1-TRUE or 0-FALSE
*********************************************************************/
unsigned char FIFO_AddOne(FIFO_Type *pFIFO, void *pValue)
{
unsigned char *p;
if (FIFO_IsFull(pFIFO))
{
return 0;
}
p = (unsigned char *)pFIFO->Buff;
memcpy(p + pFIFO->Tail * pFIFO->ElementBytes, (unsigned char *)pValue, pFIFO->ElementBytes);
pFIFO->Tail ++;
if (pFIFO->Tail >= pFIFO->Depth)
{
pFIFO->Tail = 0;
}
pFIFO->Counter ++;
return 1;
}
/********************************************************************//**
* @brief 向FIFO添加多个元素
* @param[in] pFIFO: FIFO指针
* @param[in] pValues: 要添加的元素指针
* @param[in] bytesToAdd: 要添加元素的长度
* @return 实际添加的元素个数
*********************************************************************/
unsigned int FIFO_Add(FIFO_Type *pFIFO, void *pValues, unsigned int bytesToAdd)
{
unsigned char *p;
unsigned int cnt = 0;
p = (unsigned char *)pValues;
while(bytesToAdd --)
{
if (FIFO_AddOne(pFIFO, p))
{
p += pFIFO->ElementBytes;
cnt++;
}
else
{
break;
}
}
return cnt;
}
/********************************************************************//**
* @brief 从FIFO读取一个元素
* @param[in] pFIFO: FIFO指针
* @param[in] pValue: 存放要读取的元素指针
* @return 1-TRUE or 0-FALSE
*********************************************************************/
unsigned char FIFO_GetOne(FIFO_Type *pFIFO, void *pValue)
{
unsigned char *p;
if (FIFO_IsEmpty(pFIFO))
{
return 0;
}
p = (unsigned char *)pFIFO->Buff;
memcpy(pValue, p + pFIFO->Head * pFIFO->ElementBytes, pFIFO->ElementBytes);
pFIFO->Head ++;
if (pFIFO->Head >= pFIFO->Depth)
{
pFIFO->Head = 0;
}
pFIFO->Counter --;
return 1;
}
/********************************************************************//**
* @brief 从FIFO读取多个元素
* @param[in] pFIFO: FIFO指针
* @param[out] pValues: 存放要读取的元素指针
* @param[in] bytesToRead: 要读取的元素长度
* @return 实际读取的元素个数
*********************************************************************/
unsigned int FIFO_Get(FIFO_Type *pFIFO, void *pValues, unsigned int bytesToRead)
{
unsigned int cnt = 0;
unsigned char *p;
p = pValues;
while(bytesToRead--)
{
if (FIFO_GetOne(pFIFO, p))
{
p += pFIFO->ElementBytes;
cnt++;
}
else
{
break;
}
}
return cnt;
}
/********************************************************************//**
* @brief 清空FIFO
* @param[in] pFIFO: FIFO指针
* @return None
*********************************************************************/
void FIFO_Clear(FIFO_Type *pFIFO)
{
pFIFO->Counter = 0;
pFIFO->Head = 0;
pFIFO->Tail = 0;
}
?③?串口初始化
static void MX_USART1_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.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if(HAL_UART_DeInit(&huart1) != HAL_OK)
{
Error_Handler();
}
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
/* USER CODE BEGIN USART1_Init 2 */
if(HAL_UART_Receive_DMA(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)
{
Error_Handler();
}
}
?④ 接收空闲中断
void USAR_UART_IDLECallback(UART_HandleTypeDef *huart)
{
HAL_UART_DMAStop(&huart1);
uint8_t data_length = RXBUFFERSIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
FIFO_Add(pfifo, aRxBuffer, data_length);
data_length = 0;
HAL_UART_Receive_DMA(&huart1, (uint8_t*)aRxBuffer, RXBUFFERSIZE);
}
void USER_UART_IRQHandler(UART_HandleTypeDef *huart)
{
if(USART1 == huart1.Instance)
{
if(RESET != __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
USAR_UART_IDLECallback(huart);
}
}
}
/**
* @brief This function handles USART1 global interrupt / USART1 wake-up interrupt through EXTI line 25.
*/
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1);
USER_UART_IRQHandler(&huart1);
}
⑤ 主函数调用:
#define TXBUFFERSIZE 30
/* Size of Reception buffer */
#define RXBUFFERSIZE TXBUFFERSIZE
#define RXFIFOBUFFERSIZE TXBUFFERSIZE * 5
uint8_t aTxBuffer[] = " ****UART_TwoBoards communication based on DMA****";
/* Buffer used for reception */
uint8_t aRxBuffer[RXBUFFERSIZE];
uint8_t aRxFIFOBuffer[RXFIFOBUFFERSIZE];
FIFO_Type fifo;
FIFO_Type *pfifo;
int main(void)
{
/*此处省略硬件初始化*/
if(HAL_UART_Transmit(&huart1, (uint8_t*)aTxBuffer, TXBUFFERSIZE, 200)!= HAL_OK)
{
Error_Handler();
}
pfifo = &fifo;
FIFO_Init(pfifo, aRxFIFOBuffer, sizeof(uint8_t), RXFIFOBUFFERSIZE);
while (1)
{
/*一次接收的缓存,重新发送*/
if(!FIFO_IsEmpty(pfifo))
{
uint8_t a[100]; //存放读取fifobuffer的数据
int i = pfifo->Counter;//先保存接收缓存的数据个数
FIFO_Get(pfifo, &a, pfifo->Counter);
HAL_UART_Transmit(&huart1, a, i, 200); //将接收的缓存数据再次发送,判断有无误码率
}
}
}
测试成功!可以在主函数对数据进行处理,不用担心缓存的覆盖!?
问:关于?stm32 HardFault_Handler问题处理?
ANS:
? ? ? ? 在代码调试是,发现在执行fifo_init初始化,会进入HardFault_Handler,
?
?最后,发现是在fifo_init 调用的指针,未赋地址。添加之后,解决了!
pfifo = &fifo;
参考:https://blog.csdn.net/u013184273/article/details/84440177?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-1.essearch_pc_relevant&spm=1001.2101.3001.4242
代码获取:https://download.csdn.net/download/qq_41070511/21889482
或私聊?
本人小白!望指导!(o゚v゚)ノ
参考链接:https://blog.csdn.net/a154299/article/details/86652801?spm=1001.2014.3001.5501
??????????????????https://blog.csdn.net/sea1216/article/details/104426075
? ? ? ? ? ? ? ? ?https://blog.csdn.net/xmxqiyan/article/details/43408291?utm_source=itdadao&utm_medium=referral
|