|
|
  |
STM32, USART на прерываниях и очередях, проблемы с передачей, Портится очередь |
|
|
|
Jan 20 2012, 14:14
|

Участник

Группа: Участник
Сообщений: 21
Регистрация: 28-04-08
Из: Раменсбург
Пользователь №: 37 126

|
Есть проектик, STM32F10*, FreeRTOS 7.1.0 USART реализован на прерываниях и очередях, по примеру из FreeRTOS С приемом все хорошо, а вот при передаче через некоторое время работы "портятся" данные. Свиду - сдвигаются указатели на голову и хвост в очереди. В данный момент пройтись отладчиком возможности нет. Выписал код в минипрогу, ошибка повторяется. Через некоторое, рандомное время, вместо "Hello World!\n" становится, например "rlWorld!\no Wo", потом еще что-нибудь и т.д. CODE #include "stm32f10x.h" #include "FreeRTOS.h" #include "task.h" #include "queue.h"
static xQueueHandle USART1_TxQueue;
uint8_t USART1_PutChar( uint8_t cOutChar ) { uint8_t xReturn;
if( xQueueSend( USART1_TxQueue, &cOutChar, 10 ) == pdPASS ) { xReturn = pdPASS; USART_ITConfig( USART1, USART_IT_TXE, ENABLE ); } else { xReturn = pdFAIL; }
return xReturn; }
void USART1_PutString( const uint8_t * pcString ) { uint8_t *pxNext;
pxNext = ( uint8_t * ) pcString; while( *pxNext ) { USART1_PutChar( *pxNext ); pxNext++; } }
void HelloWorldTask(void *pvParameters) { for(;;) { USART1_PutString("Hello World!\n"); vTaskDelay( 1000 ); } }
void USART1_IRQHandler( void ) { portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; uint8_t cChar;
if( USART_GetITStatus( USART1, USART_IT_TXE ) == SET ) { if( xQueueReceiveFromISR( USART1_TxQueue, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE ) { USART_SendData( USART1, cChar ); } else { USART_ITConfig( USART1, USART_IT_TXE, DISABLE ); } } portEND_SWITCHING_ISR( xHigherPriorityTaskWoken ); }
int main(void) { NVIC_InitTypeDef NVIC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure;
/* Enable USART1 GPIO clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
/* Enable UART1 clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
/* Enable the USART1 Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_LOWEST_INTERRUPT_PRIORITY; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
/* Configure USART1 Tx as alternate function push-pull */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure USART1 Rx as input floating */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure USART1 parameters 115200 8n1 noHW Tx+Rx*/ USART_InitStructure.USART_BaudRate = 115200; 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(USART1, &USART_InitStructure); USART_Cmd(USART1, ENABLE);
/* Create TxQueue for USART1 */ USART1_TxQueue = xQueueCreate( 256, ( unsigned portBASE_TYPE ) sizeof( uint8_t ) );
USART1_PutString("Program started!\n"); USART1_PutString("================\n");
xTaskCreate(HelloWorldTask, "HelWor", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
vTaskStartScheduler();
for(;;) { } }
Сообщение отредактировал asdus - Jan 20 2012, 14:16
--------------------
Секс - классная штука. Как ни крути...
|
|
|
|
|
Jan 22 2012, 19:53
|

Участник

Группа: Участник
Сообщений: 21
Регистрация: 28-04-08
Из: Раменсбург
Пользователь №: 37 126

|
Цитата(kan35 @ Jan 21 2012, 19:58)  Во первых, вы начинаете использовать queue до старта шедулера, это грубая ошибка. Спасибо за подсказку. В оригинальной программе такого небыло, прибил в тестовой. Цитата(kan35 @ Jan 21 2012, 19:58)  И на сколько мне помнится надо сбрасывать соответствующий pending bit при обработке ISR GetITStatus уже давно сбрасывает соответствующий ITPendingBit. На всякий случай добавил в тестовую прогу. Запустил тесты, ждем-с... Долго ждать не пришлось, ошибка сохранилась. К слову, с передачей, реализованной на тех-же прерываниях и очередях проблем нет, как и с передачей без использования очередей...
Сообщение отредактировал asdus - Jan 22 2012, 19:56
--------------------
Секс - классная штука. Как ни крути...
|
|
|
|
|
Jan 23 2012, 06:56
|
Знающий
   
Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594

|
Смущает вот что: бит TXE выставляется когда Цитата TXE: Transmit data register empty This bit is set by hardware when the content of the TDR register has been transferred into the shift register. Таким образом при первой записи в очередь прерывание возникнет ДВАЖДЫ, но при втором входе очередь будет пустой. Может быть не это вызывает ваш глюк, однако обратите внимание на это. Возможно проблемы с настройкой прерываний. Неплохо было бы посмотреть как freertos сконфигурирована.
|
|
|
|
|
Jan 24 2012, 08:04
|

Участник

Группа: Участник
Сообщений: 21
Регистрация: 28-04-08
Из: Раменсбург
Пользователь №: 37 126

|
Цитата(kan35 @ Jan 23 2012, 10:56)  Смущает вот что: бит TXE выставляется когда Код TXE: Transmit data register empty This bit is set by hardware when the content of the TDR register has been transferred into the shift register. Таким образом при первой записи в очередь прерывание возникнет ДВАЖДЫ, но при втором входе очередь будет пустой. Может быть не это вызывает ваш глюк, однако обратите внимание на это. Это нормально, обрабатывается ;) Цитата(kan35 @ Jan 23 2012, 10:56)  Возможно проблемы с настройкой прерываний. Неплохо было бы посмотреть как freertos сконфигурирована. Проблема была решена. Действительно, она была в настройке прерываний. Конкретно: порт FreeRTOS под STM32 требует следующей настройки: Код NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); Почему он не делает это сам - непонятно. После выполнения этой команды все стало работать как должно.
--------------------
Секс - классная штука. Как ни крути...
|
|
|
|
|
Jan 25 2012, 09:48
|

Участник

Группа: Свой
Сообщений: 66
Регистрация: 5-08-10
Из: Томск
Пользователь №: 58 761

|
С позволения ТС, задам вопрос здесь, чтобы темы не плодить. Начал осваивать FreeRTOS, и споткнулся на таком месте: создаю задачу "отложенного прерывания", которая должна отрабатывать после получения байта во USART'у. Использую для этого семафор Код xHigherPriorityTaskWoken = pdFALSE; xSemaphoreGiveFromISR( USART_RxSemaphore, &xHigherPriorityTaskWoken ); portEND_SWITCHING_ISR( xHigherPriorityTaskWoken ); Код самой задачи: Код void USART_RX_TaskHandler( void *params ) { for(;; ) { xSemaphoreTake( USART_RxSemaphore, portMAX_DELAY ); // ждем семафора
USART_puts("byte recieved\r\n"); } } и код создания задачи: Код #define USART_RX_TASKHDL_PRIORITY (configMAX_PRIORITIES-1)
// семафор для задачи получения данных по USART vSemaphoreCreateBinary( USART_RxSemaphore ); if ( USART_RxSemaphore != NULL ) { xTaskCreate( USART_RX_TaskHandler, (signed char *) "RX handler task", USART_RX_TASKHDL_STACK, NULL, USART_RX_TASKHDL_PRIORITY, NULL ); } Проблема в том, что при запуске шедулера первый раз выполняется задача USART_RX_TaskHandler, т.е. не останавливается на xSemaphoreTake (хотя по логике вроде как должна), а потом уже выполняется после "пинка" из прерывания. Подскажите это нормально или я где-то накосячил?
Сообщение отредактировал Bass - Jan 25 2012, 09:51
|
|
|
|
|
Jan 25 2012, 14:38
|
Частый гость
 
Группа: Участник
Сообщений: 99
Регистрация: 23-06-04
Из: Kiev
Пользователь №: 146

|
QUOTE (Bass @ Jan 25 2012, 13:48)  Проблема в том, что при запуске шедулера первый раз выполняется задача USART_RX_TaskHandler, т.е. не останавливается на xSemaphoreTake (хотя по логике вроде как должна), а потом уже выполняется после "пинка" из прерывания. Подскажите это нормально или я где-то накосячил? Я тоже только еще изучаю FreeRTOS. Насколько я понял, семафор, как только создан, сразу становится доступен. Поэтому задача USART_RX_TaskHandler сразу захватывает его. Так что это нормально.
|
|
|
|
|
Jan 25 2012, 16:08
|
Знающий
   
Группа: Validating
Сообщений: 838
Регистрация: 31-01-05
Пользователь №: 2 317

|
Есть такая беда у FreeRTOS нельзя при создании семафора задать его состояние. Я выкрутился созданием такого макроса: Код #define osSemNew(Sem,State,Name)\ do\ {\ Sem = xQueueCreate( ( unsigned portBASE_TYPE ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH );\ if (Sem!=NULL)\ {\ vQueueAddToRegistry(Sem,(signed char*)Name);\ if((State))\ {\ xSemaphoreGive( Sem );\ }\ }\ }while(0)\
|
|
|
|
|
Jan 25 2012, 18:11
|

Участник

Группа: Свой
Сообщений: 66
Регистрация: 5-08-10
Из: Томск
Пользователь №: 58 761

|
Ага, нашел сам макрос vSemaphoreCreateBinary, в котором видно, что после создания он сразу отдается: Код xSemaphoreGive( ( xSemaphore ) ); Тогда я думаю проще при инициализации сразу после создания взять семафор, тогда задача не выполнится до повторной выдачи уже в прерывании.
|
|
|
|
|
Jan 27 2012, 07:37
|
Местный
  
Группа: Свой
Сообщений: 366
Регистрация: 5-09-06
Из: Санкт-Петербург
Пользователь №: 20 107

|
ээээ... как показывает практика - использование очередей в уарте не есть самый лучший способ передачи данных по нескольким причинам - необходимо распределеить память под очередь - передача одного байта вызывает большой overhead - еще какие-то-там-я-и-не-помню. Более того, несмотря на то, что прерывания при низких скоростях приходят довольно-таки редко, для их обработки, тем не менее, требуется выполнить несколько действий. В stm32 можно использовать DMA на уарте и это позволяет решить проблему оверхеда. Однако без прерываний никак по-любому, однако они будут случаться только тогда, когда приемный буфер заполнен, или когда передача прекращена. При это в оси будет использоваться только один семафор. Код для stm32l152 ниже. Может кому пригодится еще. у меня работает в оч критической задаче. Код #include "stm32l1xx.h" #include "stm32l1xx_rcc.h"
#include "stm32l1xx_tim.h" #include "stm32l1xx_gpio.h" #include "stm32l1xx_spi.h" #include "stm32l1xx_dma.h" #include "stm32l1xx_usart.h"
#include "misc.h"
#include "FreeRTOS.h" #include "semphr.h" #include "task.h" #include "queue.h"
#define USART2_RX_BUF_SIZE 128 static char usart2_rx_buffer[USART2_RX_BUF_SIZE];
xSemaphoreHandle xSemaphoreUSART2;
void usart2_init(void) { USART_InitTypeDef USART_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; DMA_InitTypeDef DMA_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
USART_InitStructure.USART_BaudRate = 57600; 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(USART2, &USART_InitStructure);
USART_DMACmd(USART2, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);
/* Enable USART1 IDLE line interrupts because all others are handeled via DMA */ USART_ITConfig(USART2, USART_IT_IDLE , ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2 ); GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2 );
/* Configure USART1 Tx, RX (PA.02 PA.03) as alternate function push-pull */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Enable the USART1 Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 12; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 12; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); DMA_DeInit(DMA1_Channel6); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)usart2_rx_buffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = USART2_RX_BUF_SIZE; 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_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel6, &DMA_InitStructure);
USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 12; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 11; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
/* Enable interrupts on channel 6 */ DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE); DMA_ITConfig(DMA1_Channel6, DMA_IT_HT, ENABLE);
vSemaphoreCreateBinary( xSemaphoreUSART2 ); xSemaphoreTake( xSemaphoreUSART2, ( portTickType ) portMAX_DELAY );
USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);
USART2->SR = 0; DMA_Cmd(DMA1_Channel6, ENABLE); USART_Cmd(USART2, ENABLE); }
int usart2_send(void *buffer, int size) { DMA_InitTypeDef DMA_InitStructure;
if(size > 65535) return -2;
// if (DMA1_Channel7->CNDTR) // return -1;
while(DMA1_Channel7->CNDTR);
// now configure transmit line: // do not enable interrupts DMA_DeInit(DMA1_Channel7); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; DMA_InitStructure.DMA_BufferSize = size; 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_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel7, &DMA_InitStructure); DMA_Cmd(DMA1_Channel7, ENABLE);
return 0; }
void USART2_IRQHandler(void) { portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; int statusreg = USART2->SR; char uart_messages;
uart_messages = 0;
if(statusreg & (1<<4) ) // IDLE. ONLY this interrupt is enabled!!! { uart_messages = 3; USART2->DR; // dummy read to clear idle flag
} if(uart_messages) { xSemaphoreGiveFromISR( xSemaphoreUSART2, &xHigherPriorityTaskWoken ); }
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); }
void DMA1_Channel6_IRQHandler(void) { portBASE_TYPE xHigherPriorityTaskWoken; DMA1->IFCR = 7 << 20; // clear DMA interrupt flags and continue
xSemaphoreGiveFromISR( xSemaphoreUSART2, &xHigherPriorityTaskWoken ); portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); }
static int rx_read;
int uart2_get_char(portTickType block_time) { int res;
while(1) { if (USART2_RX_BUF_SIZE - DMA1_Channel6->CNDTR != rx_read) { res = usart2_rx_buffer[rx_read]; rx_read++; if(rx_read == USART2_RX_BUF_SIZE) rx_read = 0; return res & 0xff; }
if (pdFALSE == xSemaphoreTake( xSemaphoreUSART2, ( portTickType ) block_time )) return -1; } return 0; }
|
|
|
|
|
Jan 30 2012, 15:08
|

Участник

Группа: Участник
Сообщений: 21
Регистрация: 28-04-08
Из: Раменсбург
Пользователь №: 37 126

|
Обязательно перепишу на DMA, как только, так сразу :) Для истории пишу свой код целиком, на неэффективных прерываниях и очередях :) Как-нибудь при случае замеряю загрузку ЦП. Работает на STM32F100RB (STM32VLDISCOVERY) И не забываем запустить шулдер до использования) хотя у меня работало и до включения, но не протестировано на стабильность. CODE #include <stm32f10x.h> #include <FreeRTOS.h> #include <queue.h>
static xQueueHandle MODBUS_RxQueue; static xQueueHandle MODBUS_TxQueue;
void MODBUS_Init( void ) { NVIC_InitTypeDef NVIC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure;
/* Create Rx/Tx Queues */ MODBUS_RxQueue = xQueueCreate( 256, sizeof( uint32_t ) ); MODBUS_TxQueue = xQueueCreate( 256, sizeof( uint32_t ) ); /* Enable GPIOA clock (for USART1 TX=PA9, RX=PA10) */ RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE ); /* Enable AFIO clock (for USART1 TX) */ RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE ); /* Enable UART1 clock */ RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1, ENABLE ); /* Select NVIC Preemption Priority Group 4 (for FreeRTOS) */ NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); /* Enable the USART1 Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_LOWEST_INTERRUPT_PRIORITY; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init( &NVIC_InitStructure ); /* Configure USART1 GPIO PINs (TX=PA9, RX=PA10) */ /* Configure USART1 Tx as alternate function push-pull */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init( GPIOA, &GPIO_InitStructure ); /* Configure USART1 Rx as input floating */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init( GPIOA, &GPIO_InitStructure ); /* Configure USART1 parameters 115200 8n1 noHW Tx+Rx*/ USART_InitStructure.USART_BaudRate = 115200; 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( USART1, &USART_InitStructure ); USART_ITConfig( USART1, USART_IT_RXNE, ENABLE ); USART_Cmd( USART1, ENABLE ); }
uint8_t MODBUS_GetChar( uint8_t *pcRxedChar ) { if( xQueueReceive( MODBUS_RxQueue, pcRxedChar, 0 ) ) { return pdTRUE; } else { return pdFALSE; } }
void MODBUS_PutString( const uint8_t * pcString ) { uint8_t *pxNext;
pxNext = ( uint8_t * ) pcString; while( *pxNext ) { MODBUS_PutChar( *pxNext ); pxNext++; } }
uint8_t MODBUS_PutChar( uint8_t cOutChar ) { uint8_t xReturn;
if( xQueueSend( MODBUS_TxQueue, &cOutChar, 10 ) == pdPASS ) { xReturn = pdPASS; USART_ITConfig( USART1, USART_IT_TXE, ENABLE ); } else { xReturn = pdFAIL; }
return xReturn; }
void USART1_IRQHandler( void ) { portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; uint8_t cChar;
if( USART_GetITStatus( USART1, USART_IT_TXE ) == SET ) { if( xQueueReceiveFromISR( MODBUS_TxQueue, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE ) { USART_SendData( USART1, cChar ); } else { USART_ITConfig( USART1, USART_IT_TXE, DISABLE ); } } if( USART_GetITStatus( USART1, USART_IT_RXNE ) == SET ) { cChar = USART_ReceiveData( USART1 ); xQueueSendFromISR( MODBUS_RxQueue, &cChar, &xHigherPriorityTaskWoken ); } portEND_SWITCHING_ISR( xHigherPriorityTaskWoken ); }
--------------------
Секс - классная штука. Как ни крути...
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|