在固定间隔后通过STM32(Bluepill)接收到固定间隔后的角色
我试图通过UART1从Atmega 328p不断地发送一个“ Hello”字符串到Bluepill板。我正在通过中断进行接收。 问题是几次后,它开始在我的串行显示器上给“ Ello”“ Hello”,我无法弄清楚什么问题。 波特率-9600 奇偶校验 - 无 stop bit-1
main.c:
usart_irq在此处称为“ USART代码在此处开始”下:
#include "main.h"
#include "uart.h"
UART_HandleTypeDef huart1;
char *readBuffer;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
/* USER CODE END 2 */
接收到的字符串使用ReadString存储在“ dechBuffer”中,并使用使用该串行监视器打印到序列显示我创建了一个单独的UART库。
while (1)
{
/* USER CODE END WHILE */
readBuffer=serialReadString1();
writeString1(readBuffer);
HAL_Delay(500);
/* USER CODE BEGIN 3 */
}
usart1_irqhandler
我启用了全局中断,并在那里称为接收函数,并使用了返回,因为我不想使用hal_irq:
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
receivestring1();
return;
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
uart.c
写字符串:
#include"main.h"
#include "uart.h"
#define RX_BUFFER_SIZE1 144
char rxBuffer1[RX_BUFFER_SIZE1];
uint16_t rx1ReadPos;
void sendChar1( uint8_t ch)
{
while(!(USART1->SR & USART_SR_TXE));
USART1->DR = ch;
}
void writeString1(const char c[])
{
uint16_t i = 0;
for (i = 0; i<= strlen(c); i++)
{
sendChar1(c[i]);
}
memset(rxBuffer1,0,RX_BUFFER_SIZE1);
rx1ReadPos = 0;
}
用于阅读 :细绳:
unsigned char receivedChar1(void)
{
while(!(USART1->SR & USART_SR_RXNE));//check whether any tx is going on
return USART1->DR;
}
void receivestring1()
{
while(!(USART1->SR & USART_SR_RXNE));//check whether any tx is going on
rxBuffer1[rx1ReadPos] = USART1->DR;
if (rxBuffer1[rx1ReadPos] != '\n')
{
rx1ReadPos++;
if (rx1ReadPos >= RX_BUFFER_SIZE1)
{
rx1ReadPos = 0;
}
}
}
char* serialReadString1()
{
return rxBuffer1;
}
I am trying to send a string "hello" continiously through UART1 from Atmega 328P to the BLUEPILL board. I am doing the reception by by interrupt.
The problem is after few times it starts to give "ello" "hello" alternatively on my serial monitor, I am not able to figure out whats going wrong.
BAUD RATE-9600
parity bit- NONE
STop bit- 1
main.c:
The usart_IRQ is called here under "usart code begin here":
#include "main.h"
#include "uart.h"
UART_HandleTypeDef huart1;
char *readBuffer;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
/* USER CODE END 2 */
The string received is stored in the "readBuffer" using the readstring and the printed to the serial monitor using the writestring forwhich i created a separate UART library.
while (1)
{
/* USER CODE END WHILE */
readBuffer=serialReadString1();
writeString1(readBuffer);
HAL_Delay(500);
/* USER CODE BEGIN 3 */
}
USART1_IRQHandler
I have enabled the Global interrupt and called the received function there, and used the return because I dont want to use the HAL_irq:
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
receivestring1();
return;
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
uart.c
for write string:
#include"main.h"
#include "uart.h"
#define RX_BUFFER_SIZE1 144
char rxBuffer1[RX_BUFFER_SIZE1];
uint16_t rx1ReadPos;
void sendChar1( uint8_t ch)
{
while(!(USART1->SR & USART_SR_TXE));
USART1->DR = ch;
}
void writeString1(const char c[])
{
uint16_t i = 0;
for (i = 0; i<= strlen(c); i++)
{
sendChar1(c[i]);
}
memset(rxBuffer1,0,RX_BUFFER_SIZE1);
rx1ReadPos = 0;
}
for read string:
unsigned char receivedChar1(void)
{
while(!(USART1->SR & USART_SR_RXNE));//check whether any tx is going on
return USART1->DR;
}
void receivestring1()
{
while(!(USART1->SR & USART_SR_RXNE));//check whether any tx is going on
rxBuffer1[rx1ReadPos] = USART1->DR;
if (rxBuffer1[rx1ReadPos] != '\n')
{
rx1ReadPos++;
if (rx1ReadPos >= RX_BUFFER_SIZE1)
{
rx1ReadPos = 0;
}
}
}
char* serialReadString1()
{
return rxBuffer1;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我可以在您的代码中发现几个潜在问题:
您不应该跳过
hal_uart_irqhandler()
在usart1_irqhandler()
中的调用。通常需要在中断控制器(NVIC)和/或相应的外围单元(在您的情况下)中中断(已清除)。如果没有这样做,您可能会立即将中断处理程序再次召唤,尽管没有真正的新事件。while(!(usart1-&gt; sr&amp; usart_sr_rxne)))
在receed> receed> receed> receed char1()
and code> rechivestring1()的开头。不需要必要,因为只有在RX不为空时才能生成中断。您的中断配置看起来正确,因此仅由于问题1(见上文)可能需要这是必要的。变量
rxbuffer1
和rx1ReadPos
在evevesivestring1()
and code> writestring1()中都操纵。由于rechivestring1()
是从usart1_irqhandler()
调用writestring1()
从main(Main()
调用此操作实际上可以并行发生。这可能会成为问题,原因有两个:rxBuffer1
的内容可能会在任何情况下发生变化(例如,在处理 for forwitteString1() loop时>)。可以通过将
loop的volatile
关键字添加到rxbuffer1
,rx1ReadPos
以及writestring1()
的参数。这样,编译器将重新评估strlen(c)
在的每个通过中。
rx1ReadPos
几乎同时,例如,之前的那一刻,当
在evereivestring1()
收到新字符时rx1ReadPoswritestring1()
中重置为零,这将导致失去该字符。这称为A 种族条件,只能通过在有限的时间内阻止中断,或者以确保该并行执行不能导致数据损失的方式来避免。一种可能的解决方案可能是使用两个单独的缓冲区 - 一个用于接收和一个用于写作的缓冲区。writestring1()
是通过sendchar1()
将字符写入接收数据的同一UART1。这主要不是可以的,但是发送数据是使用相同的慢速9600波特速率。这真的很可能是,writestring1()
被usart1_irqhandler()
中断,即收到其他数据。最好将配置为更高BAUD率的其他UART用于调试目的。我想您的
“ Ello”
问题主要由问题3引起。附录
以检查STM32是否正确接收Atmega的字符,可以通过直接从中断处理程序发送每个接收的字符来简化代码(避免异步缓冲区处理的复杂性)。
这可能是这样的:
Addendum#2
通过请求是草图如何改进缓冲区的方法:
注:
此草图试图尽可能少地修改代码。关键想法是:
rxbuffer1
和rxbuffer2
) - 一个用于接收数据,一个用于再次将接收到的数据发送。main()
serialReadString1()中请求缓冲区 。缓冲区切换本身是在ISR内完成的,以避免任何种族条件。serialReadString1()
中的操作顺序:首先,在switchbufferrequest
设置为true 因为
rxbufferptr
可能会在此后的任何时间更改。writestring1()
仅通过删除rxbufferpos
(现在在ISR中完成)的重置并清除Rx Buffer,而不是不是 使用, 。 RX ISR。I can spot several potential issues in your code:
You should not skip the call of
HAL_UART_IRQHandler()
inUSART1_IRQHandler()
. Each interrupt usually needs to be acknowledged (cleared) in either the interrupt controller (NVIC) and/or the respective peripheral unit (the UART in your case). If this is not done, you might end up with the interrupt handler being called again right away, although there has not been a real new event.The
while(!(USART1->SR & USART_SR_RXNE))
at the start ofreceivedChar1()
andreceivestring1()
should not be necessary, since the interrupt should only be generated if the RX is not empty. Your interrupt configuration looks correct, so this might be only necessary due to issue #1 (see above).The variables
rxBuffer1
andrx1ReadPos
are manipulated both inreceivestring1()
andwriteString1()
. Sincereceivestring1()
is called fromUSART1_IRQHandler()
whilewriteString1()
is called frommain()
this manipulation can happen virtually in parallel. This can become problematic for two reasons:rxBuffer1
might change at any (e.g. also while processing thefor
loop inwriteString1()
). This can be avoided by adding thevolatile
keyword torxBuffer1
,rx1ReadPos
and also the argument ofwriteString1()
. This way the compiler will re-evaluatestrlen(c)
on every pass of thefor
loop.rx1ReadPos
at virtually the same time, e.g. when a new character is received byreceivestring1()
just in the moment beforerx1ReadPos
is reset to zero inwriteString1()
, which would lead to losing that character. This is called a race-condition and can only be avoided by either blocking interrupts for a limited time or by constructing the code in a way that makes sure, that parallel execution can not lead to data-loss. One possible solution could be the use of two separate buffers - one used for receiving and one used for writing.writeString1()
is writing the characters viasendChar1()
to the same UART1 that is receiving the data. This is not a principally okay but sending the data is thus using the same slow 9600 baud-rate. This makes it really probable, thatwriteString1()
gets interrupted byUSART1_IRQHandler()
, i.e. that additional data is received. It might be better to use a different UART configured to a higher baud-rate for debug purposes.I suppose that your
"ello"
problem is primarily caused by issue #3.Addendum
To check whether the stm32 correctly receives the characters from the Atmega you could simplify your code by sending out each received character directly from the interrupt handler (avoiding the complexity of the asynchronous buffer handling).
This could look like this:
Addendum #2
By request here is a sketch how the buffer handling could be improved:
Note:
This sketch tries to modify your code as little as possible. The key ideas are:
rxBuffer1
andrxBuffer2
) -- one for receiving data and one for sending received data out again.main()
serialReadString1()
via the flagSwitchBufferRequest
. Buffer switching itself is done within the ISR to avoid any race conditions.serialReadString1()
: First the pointer to the latest received data is copied in a separate variable beforeSwitchBufferRequest
is set totrue
becauserxBufferPtr
might change at any time afterwards.writeString1()
is only modified slightly by removing the reset ofrxBufferPos
(now done in ISR) and clearing the RX buffer which is not used by the RX ISR.