Hello Here is my USART's settings:
USART_InitTypeDef USAR; GPIO_InitTypeDef GPIOStruc; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_AFIO,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); GPIO_PinRemapConfig(GPIO_Remap_USART1,ENABLE); GPIOStruc.GPIO_Mode=GPIO_Mode_AF_PP ; GPIOStruc.GPIO_Speed=GPIO_Speed_50MHz; GPIOStruc.GPIO_Pin=GPIO_Pin_6; GPIO_Init(GPIOB,&GPIOStruc); GPIOStruc.GPIO_Mode=GPIO_Mode_IN_FLOATING ; GPIOStruc.GPIO_Pin=GPIO_Pin_7; GPIO_Init(GPIOB,&GPIOStruc); USAR.USART_BaudRate=115200; USAR.USART_StopBits=USART_StopBits_1; USAR.USART_WordLength=USART_WordLength_8b; USAR.USART_Parity=USART_Parity_No ; USAR.USART_HardwareFlowControl=USART_HardwareFlowControl_None; USAR.USART_Mode=USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1,&USAR); USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); NVIC_EnableIRQ(USART1_IRQn); USART_Cmd(USART1,ENABLE);
and I send 200 characters with printf function each 20ms(that created by timer).
timer settings
TIM_TimeBaseInitTypeDef TimeStruct; NVIC_InitTypeDef nvicStructure; nvicStructure.NVIC_IRQChannel = TIM2_IRQn; nvicStructure.NVIC_IRQChannelPreemptionPriority = 0; nvicStructure.NVIC_IRQChannelSubPriority = 1; nvicStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&nvicStructure); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); TimeStruct.TIM_Prescaler=7200; TimeStruct.TIM_Period=200; TimeStruct.TIM_ClockDivision=TIM_CKD_DIV1; TimeStruct.TIM_CounterMode= TIM_CounterMode_Up ; TimeStruct.TIM_RepetitionCounter =0; TIM_TimeBaseInit(TIM2, &TimeStruct); TIM_Cmd(TIM2, ENABLE); TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
printf("LOng string......");
struct __FILE { int handle;} ; FILE __stdout; FILE __stdin; FILE __stderr; int fputc(int ch, FILE *f) { while(!USART_GetFlagStatus(USART1,USART_FLAG_TXE)); USART_SendData(USART1,ch); return ch;
but when I send a 120 characters string to my device it doesn't do anything
void USART1_IRQHandler(void){ if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { temp=USART_ReceiveData(USART1); } }
but when I increase timer step (for example 100ms) it works fine. what's wrong with it ? what is my mistake?
Thanks dear Per Westermark
would it be possible to give me an example of "you instead use two pointers to the buffers. It's enough to swap the value of the two pointers."?
Next thing - why zero the buffer when starting to receive a new message? It's enough to keep track of the insert position until you have a complete message in which case you can hand over that message. You can even hand over the exact packet length if you want.
because I've wanted to set the first character's position at the first position of my array and prevent from overflow.(but it can be solved easily if I can save my characters)
Why "stat" instead of something like "is_receiving_packet"? Why "flag" instead of something like "have_packet_ready"?
Actually I've wanted to change their name for this forum and after my code works but I was too lazy and didn't have much more time such as before.(I will do)
Note also that unless your code allows nested interrupts, a long function call in TIM2_IRQHandler() (such as the printf()) can create too much latency so USART1_IRQHandler() doesn't get called before you get an overrun in the UART and lose characters.
would it possible to know your idea about "how can I send a string each 20ms without less latency" ? I've changed my code as shown below.but it doesn't work as the old one.
void TIM2_IRQHandler(){ if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) { if(dat==0){ //some calculations before send send(); } else { dat=dat-1; } TIM_ClearITPendingBit(TIM2, TIM_IT_Update); } } void send(void){ char msg[200]; int i; sprintf(msg,"AAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBAAAAAAAAAAAAAAACCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDIIIIIIIIIIUUUUUUU"); for(i=0;i<150;i++){ if(msg[i]=='\0')break; while(!USART_GetFlagStatus(USART1,USART_FLAG_TXE)); if(dat!=0){break;} USART_SendData(USART1,msg[i]); } }
char buf1[BUFSIZE]; char buf2[BUFSIZE]; volatile unsigned delivered_msg_size = 0; volatile char *delivered_msg = NULL; volatile char *tmp_msg = buf1; void loop() { for (;;) { if (delivered_msg) { process_msg(delivered_msg,delivered_msg_size); delivered_msg = NULL; } ... } } void uart_irq() { static unsigned insert_pos = 0; static unsigned in_packet = FALSE; ... if (c == START_CHAR) { insert_pos = 0; in_packet = TRUE; } else if (!in_packet) { // ignore char } else if (c == END_CHAR) { if (delivered_msg) { // main loop hasn't processed data fast enough... // throw away this new packet! } else { delivered_msg_size = insert_pos; delivered_msg = tmp_msg; tmp_msg = (tmp_msg == buf1) ? buf2 : buf1; } in_packet = FALSE; } else if (!valid_char(c)) { // invalid data - fail packet in_packet = FALSE; } else if (insert_pos >= BUFSIZE) { // too much data - fail packet in_packet = FALSE; } else { tmp_msg[insert_pos++] = c; } ... }
Reserve one additional position in the buffer and zero-terminate just before hand-over, in case you want the final buffer to be zero-terminated so you can directly print it.
Then you can also decide to not hand over any message size.
Thanks a zillion for you masterfully code Actually I've changed my received code and it works better but still missing characters exist it seems it is related to timer code and it's output and " if(dat!=0){break;}" didn't prevent from this problem
Make use of UART transmit interrupts to send.
If each message to send should differ, then have the main loop create the strings.
Let the timer interrupt activate the UART transmission - the UART ISR will then pick up new characters as they are consumed. When the last character has transmitted, then turn off the UART TX interrupt and leave off until the timer ISR kick-starts the next transmission.
With a quick timer ISR, you get less latency issues from concurrently pending interrupt sources.
Hurraa... Thank you Per Westermark Now it works fine with USART transmit interrupts. Thanks a zillion for accompany me and your good explanation