[英]STM32 Timer Counter problem during sending data via UART
我在代码(STM32F303RE)中处理定时器有一些问题。 我的目标是每 200 毫秒(一个数据包)和每 1 秒(第二个数据包)向 UART 端口发送消息。 我实现了定时器( MX_TIM6_Init ),它每 100 毫秒( HAL_TIM_PeriodElapsedCallback )增加 2 个变量( timer100ms和timer1000ms )。
代码有什么作用?
在正常操作中向 UART 发送消息。 时间和数据都还可以——这里一切正常。 当其他设备要向 STM32 发送信息时,首先发送一个“ED”帧,这会将标志( flag_UART_SEND_DATA 更改为FALSE )并关闭主循环中的所有通信。 然后它发送相关帧并等待具有相同帧的响应(回声)。
当代码注释了有关检查计时器和数据值的部分时,一切正常(即使每 100ms-120ms 发送一次数据):
if (flag_UART_SEND_DATA == TRUE) {
// if (timer100ms >= 2) {
Print_CAN_Frame("Tx", IPC_Ligths.ID, IPC_Ligths.DLC, IPC_Ligths.CAN_Tx);
HAL_Delay(5);
Print_CAN_Frame("Tx", IPC_SpeedOdometerInfo.ID, IPC_SpeedOdometerInfo.DLC, IPC_SpeedOdometerInfo.CAN_Tx);
HAL_Delay(5);
Print_CAN_Frame("Tx", IPC_SpeedOdometerInfo.ID, IPC_SpeedOdometerInfo.DLC, IPC_SpeedOdometerInfo.CAN_Tx);
HAL_Delay(5);
Print_CAN_Frame("Tx", IPC_SpeedOdometerInfo.ID, IPC_SpeedOdometerInfo.DLC, IPC_SpeedOdometerInfo.CAN_Tx);
HAL_Delay(5);
timer100ms = 0;
// } else if (timer1000ms == 10) {
Print_CAN_Frame("Tx", IPC_StatusBCM.ID, IPC_StatusBCM.DLC, IPC_StatusBCM.CAN_Tx);
HAL_Delay(100);
timer100ms = 0;
timer1000ms = 0;
// }
}
问题出现在哪里?
当部分未注释如下时。 已发送帧之间的间隔较大,尽管如此,代码仍无法正常工作。 当任何消息被发送时(例如通过 TeraTerm),只有发送消息的前两个字符被接收作为响应(例如通过发送HELLO给出HE )。 出现问题时的唯一区别是主循环中的部分。 UART 发送到设备的帧完全进入,完整数据被传递到HAL_UART_TRANSMIT_IT (在HAL_UART_RxCpltCallback中)和 HAL_UART_TRANSMIT_IT 返回 HAL_OK -> 但在控制台上它只发送 2 个字符。 您有什么想法/建议要检查更多/问题出在哪里?
if (flag_UART_SEND_DATA == TRUE) {
if (timer100ms >= 2) {
Print_CAN_Frame("Tx", IPC_Ligths.ID, IPC_Ligths.DLC, IPC_Ligths.CAN_Tx);
HAL_Delay(5);
Print_CAN_Frame("Tx", IPC_SpeedOdometerInfo.ID, IPC_SpeedOdometerInfo.DLC, IPC_SpeedOdometerInfo.CAN_Tx);
HAL_Delay(5);
Print_CAN_Frame("Tx", IPC_SpeedOdometerInfo.ID, IPC_SpeedOdometerInfo.DLC, IPC_SpeedOdometerInfo.CAN_Tx);
HAL_Delay(5);
Print_CAN_Frame("Tx", IPC_SpeedOdometerInfo.ID, IPC_SpeedOdometerInfo.DLC, IPC_SpeedOdometerInfo.CAN_Tx);
HAL_Delay(5);
timer100ms = 0;
} else if (timer1000ms == 10) {
Print_CAN_Frame("Tx", IPC_StatusBCM.ID, IPC_StatusBCM.DLC, IPC_StatusBCM.CAN_Tx);
HAL_Delay(5);
timer100ms = 0;
timer1000ms = 0;
}
}
完整代码:
#define TRUE 1
#define FALSE 0
#define FIFO_BUFFER g_rxFifo;
#define USART_HEADER_LENGTH 6
#define USART_ID_LENGTH 7
#define USART_DLC_LENGTH 1
#define USART_MAX_MESSAGE_LENGTH 17
#define USART_DLC_LOCATION 23
#define LENGTH_CARRIGE_RETURN_SIGN 1
TIM_HandleTypeDef htim6;
UART_HandleTypeDef huart2;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_TIM6_Init(void);
void SystemClockConfig(void);
void UART2_Init(void);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);
void Clear_Array(uint8_t array[], uint16_t size);
void Print_CAN_Frame(char CanFrameName[], uint32_t CanID, uint32_t CanDlc, uint8_t CANmsg[]);
void Parse_From_UART(char CanFrame[]);
uint8_t* Convert_To_HEX(char *string);
void Save_Data_To_CAN_Frame(CAN_MessageTypeDef canBuffer);
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
CAN_MessageTypeDef canUartBuffer;
uint32_t timer100ms = 0;
uint32_t timer1000ms = 0;
uint8_t uint_8Buffer[70];
uint8_t data_buffer[70];
uint32_t count = 0;
uint8_t rcvd_data;
uint8_t flag_UART_TX_COMPLETED = FALSE;
uint8_t flag_UART_RX_COMPLETED = FALSE;
uint8_t flag_UART_SEND_DATA = TRUE;
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_USART2_UART_Init();
MX_TIM6_Init();
HAL_UART_Receive_IT(&huart2, &rcvd_data, 1);
HAL_TIM_Base_Start_IT(&htim6);
while (1)
{
if (flag_UART_SEND_DATA == TRUE) {
// if (timer100ms >= 2) {
Print_CAN_Frame("Tx", IPC_Ligths.ID, IPC_Ligths.DLC, IPC_Ligths.CAN_Tx);
HAL_Delay(5);
Print_CAN_Frame("Tx", IPC_SpeedOdometerInfo.ID, IPC_SpeedOdometerInfo.DLC, IPC_SpeedOdometerInfo.CAN_Tx);
HAL_Delay(5);
Print_CAN_Frame("Tx", IPC_SpeedOdometerInfo.ID, IPC_SpeedOdometerInfo.DLC, IPC_SpeedOdometerInfo.CAN_Tx);
HAL_Delay(5);
Print_CAN_Frame("Tx", IPC_SpeedOdometerInfo.ID, IPC_SpeedOdometerInfo.DLC, IPC_SpeedOdometerInfo.CAN_Tx);
HAL_Delay(5);
timer100ms = 0;
// } else if (timer1000ms == 10) {
Print_CAN_Frame("Tx", IPC_StatusBCM.ID, IPC_StatusBCM.DLC, IPC_StatusBCM.CAN_Tx);
HAL_Delay(100);
timer100ms = 0;
timer1000ms = 0;
// }
}
while((flag_UART_RX_COMPLETED && flag_UART_TX_COMPLETED))
{
if (data_buffer[0] == 'S' || data_buffer[0] =='E') // if received data is START / END tx Transmission:
{
Clear_Array(data_buffer, strlen(data_buffer));
count = 0;
flag_UART_RX_COMPLETED = FALSE;
flag_UART_TX_COMPLETED = FALSE;
HAL_UART_Receive_IT(&huart2, &rcvd_data, 1);
} else {
count = 0;
//Parse_From_UART(data_buffer);
//Save_Data_To_CAN_Frame(canUartBuffer);
Clear_Array(data_buffer, 70);
flag_UART_RX_COMPLETED = FALSE;
flag_UART_TX_COMPLETED = FALSE;
}
}
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (rcvd_data == '\r') {
data_buffer[count++] = '\r';
flag_UART_RX_COMPLETED = TRUE;
if (data_buffer[0] == 'S' && data_buffer[1] == 'T') {
flag_UART_SEND_DATA = TRUE;
}
else if ((data_buffer[0] == 'E' && data_buffer[1] == 'D') || (data_buffer[0] == 'E' && data_buffer[1] == 'E')) {
flag_UART_SEND_DATA = FALSE;
HAL_UART_Transmit_IT(&huart2, data_buffer, count);
while (HAL_UART_GetState(&huart2) != HAL_UART_STATE_BUSY_TX);
count = 0;
HAL_UART_Receive_IT(&huart2, &rcvd_data, 1);
return;
}
if (HAL_UART_Transmit_IT(&huart2, data_buffer, count) != HAL_OK)
{
Error_Handler(); // if HAL_ERROR
}
count = 0;
}
else
{
data_buffer[count++] = rcvd_data;
}
HAL_UART_Receive_IT(&huart2, &rcvd_data, 1);
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
flag_UART_TX_COMPLETED = TRUE;
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
timer100ms=timer100ms+1;
timer1000ms=timer1000ms+1;
}
static void MX_TIM6_Init(void)
{
htim6.Instance = TIM6;
htim6.Init.Prescaler = 119;
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
htim6.Init.Period = (59999);
if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
{
Error_Handler();
}
}
void Print_CAN_Frame(char CanFrameName[], uint32_t CanID, uint32_t CanDlc, uint8_t CANmsg[])
{
char buffer[70] = {0};
sprintf(buffer,"CAN_%s| ID:0x%02X| DLC:%d| FRAME: ",CanFrameName,(unsigned int)CanID,(unsigned int)CanDlc);
for (uint16_t i = 0; i<CanDlc; i++)
{
sprintf(buffer+strlen(buffer),"%02X ",*(CANmsg+i)); // print all DATA elements one by one
}
sprintf(buffer+strlen(buffer),"\n\r");
Clear_Array(uint_8Buffer, 70);
for (uint8_t i = 0U; i<strlen(buffer);i++)
{
uint_8Buffer[i] = (uint8_t)buffer[i];
}
if (HAL_UART_Transmit_IT(&huart2, uint_8Buffer, strlen(buffer)) != HAL_OK)
{
Error_Handler();
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2;
PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
static void MX_USART2_UART_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
}
@更新
我找到了一个部分解决方案——我降低了定时器中断的优先级,以便 UART 具有更高的优先级。 对于更大的时间(500 毫秒),它似乎可以工作,但这个解决方案仍然不能满足我 - 它不稳定。 更重要的是,300ms定时器只有在设备处于调试模式时才能正常工作。 关闭调试器后,设备无法正常工作。
首先,您需要将volatile
关键字添加到在中断处理程序 (ISR) 中更改并从主循环读取的所有(全局)变量中,即:
volatile uint32_t timer100ms = 0;
volatile uint32_t timer1000ms = 0;
volatile uint32_t count = 0;
volatile uint8_t flag_UART_TX_COMPLETED = FALSE;
volatile uint8_t flag_UART_RX_COMPLETED = FALSE;
volatile uint8_t flag_UART_SEND_DATA = TRUE;
这告诉编译器,变量的值可能随时改变(即通过中断)。 否则,编译器可能会通过在第一次访问此类变量时仅读取一次该变量的值来优化代码。 这将导致问题,因为 ISR 对变量所做的部分或全部更改将被遗漏。 这可能会导致意外或未定义的行为。 由于在调试模式下通常会降低优化级别,因此此类代码可能适用于调试版本,但不适用于发布版本。
注意: volatile
关键字不保证对这些变量的原子访问。 在 STM32 设备上,对uint8_t
和uint32_t
等小类型的读取或写入访问是隐式原子的,因为 MCU 始终将这些类型作为一个整体进行读取/写入。 在读取-修改-写入操作或访问较大类型(如struct
)的情况下,您需要采取额外措施以确保数据始终一致(即在主循环中读取时不会在中断内更改)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.