Применение очередей при работе с UART.




Для работы с UART и со стандартными библиотечными функциями потокового ввода/вывода printf() и scanf() создаются 2 очереди:

· Очередь stdin_queue предназначена для приема данных через UART.

· Очередь stdout_queue предназначена для передачи данных через UART.

 

Работа с очередью stdin_queue для приема данных через UART.

Запись элемента в очередь stdin_queue.

Обработчик прерывания по приему по UART - UART2_IRQHandler() помещает принятый байт данных в локальную переменную
ReceiveByte = UART_ReceiveData(UART_IO).

Значение переменной ReceiveByte отправляется в конец очереди stdin_queue: xQueueSendToBackFromISR(stdin_queue, &ReceiveByte, &xHigherPriorityTaskWoken).

Чтение элемента из очереди stdin_queue.

Функция scanf() является стандартной библиотечной функцией потокового ввода. Функция fgetc(), находящаяся в файле uart_io.c, читает один байт из потокового ввода и вызывается из функции scanf(). Функция fgetc() должна быть переопределена для чтение одного байта из очереди stdin_queue. Вызов функции scanf() из любой задачи, по сути, будет обращаться к данным очереди stdin_queue.

Работа с очередью stdout_queue для передачи данных через UART.

Запись элемента в очередь stdout_queue.

Функция printf() является стандартной библиотечной функцией потокового вывода. Функция fputc(), находящаяся в файле uart_io.c, передает один байт из потокового вывода и вызывается из функции printf(). Функция fputc() должна быть переопределена для передачи одного байта в очередь stdout_queue. Вызов функции printf() из любой задачи, по сути, будет формировать данные очереди stdout_queue.

Чтение элемента из очереди stdout_queue.

Вывод данных по UART организован в отдельной низкоприоритетной задачи: Task_Output. В этой задаче происходит чтение элемента из очереди stdout_queue в переменную buffer и передача значения этой переменной через UART с помощью функции UART_SendData(UART_IO, buffer). Передача будет производиться пока задача не передаст все символы из очереди. Если задача блокируется планировщиком из-за вызова более высокоприоритетной задачи, то передача символов продолжится после блокировки более высокоприоритетной задачи.

 


 

Для работы со стандартными библиотечными функциями потокового ввода/вывода printf() и scanf() были переопределены функции посимвольного ввода вывода fputc() и fgetc(). Данные функции осуществляли по символьный ввод/вывод в 2 очереди для ввода и вывода:

Функции fputc() и fgetc():

1. extern xQueueHandle stdin_queue;

2. extern xQueueHandle stdout_queue;

3.

4. /**

5. * @brief Retargets the C library printf function to the UART.

6. */

7. int fputc(int ch, FILE *f)

8. {

9. char item = (char)ch;

10.

11. xQueueSendToBack(stdout_queue, &item, 0);

12. return ch;

13. }

14.

15. /**

16. * @brief Retargets the C library scanf function to the UART.

17. */

18. int fgetc(FILE *f)

19. {

20. uint8_t ch;

21.

22. if (xQueueReceive(stdin_queue, &ch, portMAX_DELAY) == pdPASS)

23. {

24. return((int)ch);

25. }

26. else

27. {

28. return ((int)'\0');

29. }

30. }

По приему данных по UART разрешены прерывания, для этого в функции инициализации UART uart_io_init() необходимо добавить 2 строки:

1. /*Разрешение прерывания для UART*/

2. NVIC_EnableIRQ(UART_IO_IRQ);

3. /*Разрешение прерывания по приему*/

4. UART_ITConfig(UART_IO,UART_IT_RX, ENABLE);

Подпрограмма обработчик прерывания по приему данных по UART:

1. void UART2_IRQHandler(void)

2. {

3. static uint8_t ReceiveByte=0x00; // данные для приема

4. static BaseType_t xHigherPriorityTaskWoken;

5. //проверка установки флага прерывания по окончании приема данных

6. if (UART_GetITStatusMasked(MDR_UART2, UART_IT_RX) == SET)

7. {

8. //очистка флага прерывания по приему данных

9. UART_ClearITPendingBit(MDR_UART2, UART_IT_RX);

10. }

11. // записать принятый данный в статическую переменную

12. ReceiveByte=UART_ReceiveData(UART_IO);

13. //Отправить принятый байт в очередь приема данных

14. xQueueSendToBackFromISR(stdin_queue, &ReceiveByte, &xHigherPriorityTaskWoken);

15. // Принудительно переключить контекст, вызов планировщика для передачи управления задаче с более высоким приоритетом, если она разблокировалась

16. portYIELD_FROM_ISR(xHigherPriorityTaskWoken);

17. }

Значение *pxHigherPriorityTaskWoken необходимо отслеживать для того, чтобы выполнить переключение контекста задачи в конце обработчика прерывания, если в результате отправки в очередь была разблокирована более высокоприоритетная задача. Если этого не сделать, то после выполнения обработчика прерывания выполнение продолжит та задача, выполнение которой были прервано этим прерыванием. Ничего «страшного» в этом случае не произойдет: текущая задача будет выполняться до истечения текущего кванта времени, после чего планировщик выполнит переключение контекста (которое он выполняет каждый системный квант), и управление получит более высокоприоритетная задача. Единственное, что пострадает, — это время реакции системы на прерывание, которое может составлять до одного системного кванта.

 

Основная функция программы main.c:

1. /* Объявить переменную-дескриптор очереди. Эта переменная

2. будет использоваться для ссылки на очередь после ее создания. */

3. xQueueHandle stdin_queue,stdout_queue;

4.

5. // Создание очередей для потока ввода/вывода

6. stdin_queue = xQueueCreate(STDIN_QUEUE_SIZE, sizeof(char));

7. stdout_queue = xQueueCreate(STDOUT_QUEUE_SIZE, sizeof(char));

8.

9. //Создание задачи по работе с меню

10. xTaskCreate(U_MENU_Task_Function,

11. (char *) "Task1",

12. configMINIMAL_STACK_SIZE,

13. NULL,

14. tskIDLE_PRIORITY + 2,

15. NULL);

16. //Создание задачи по выводу бегущей строки на ЖКИ

17. xTaskCreate(U_MENU_Running_String_Task_Function,

18. (char *) "Task2",

19. configMINIMAL_STACK_SIZE,

20. NULL,

21. tskIDLE_PRIORITY + 2,

22. NULL);

23. //Создание задачи по выводу на ЖКИ информации полученной с терминала по UART

24. xTaskCreate(U_MENU_Output,

25. (char *) "Task3",

26. configMINIMAL_STACK_SIZE,

27. NULL,

28. tskIDLE_PRIORITY + 2,

29. NULL);

30. //Создание задачи приветствия

31. xTaskCreate(U_Privet,

32. (char *) "Task4",

33. configMINIMAL_STACK_SIZE,

34. NULL,

35. tskIDLE_PRIORITY + 3,

36. NULL);

37. //Создание задачи для работы с выводом по UART – самая низкоприоритетная задача

38. xTaskCreate(Task_output,

39. (char *) "Task5",

40. configMINIMAL_STACK_SIZE,

41. NULL,

42. tskIDLE_PRIORITY + 1,

43. NULL);

44.

45. // Запуск планировщика задач

46. vTaskStartScheduler();

47. }

 

 

Добавленные задачи:

1. //Задача по выводу на ЖКИ информации полученной с терминала по UART

2. void U_MENU_Output (void)

3. {

4. /* Буфер для полученного сообщения по UART */

5. char Message_UART[16 + 1];

6. while(1)

7. {

8. // Ожидание ввода сообщения по UART

9. scanf("%16s", Message_UART);

10. // Передача полученного ссобщения на дисплей ЖКИ в 4-ю строку

11. U_MLT_Put_String (Message_UART, 4);

12. // Передача в стандартный поток вывода, что сообщение успешно передано на ЖКИ

13. printf("Transmit Message To LCD - Success\r\n");

14. }

15. }

16.

17. // Задача - приветствие

18. void U_Privet(void)

19. {

20. // Отправка сообщения приветствия

21. printf("Work with Queues\r\n");

22. // Удаление задачи

23. vTaskDelete(NULL);

24. }

25.

26. // Задача для работы с выводом по UART - Самая низкоприоритетная задача

27. void Task_output(void)

28. {

29. static uint8_t buffer;

30. while(1)

31. {

32. if (xQueueReceive(stdout_queue, &buffer, portMAX_DELAY) == pdPASS)

33. {

34. //Ожидание флага освобождения буфера передачи (TXFE) */

35. while (UART_GetFlagStatus(UART_IO, UART_FLAG_TXFE)!= SET);

36. // Отправка одного символа по UART

37. UART_SendData(UART_IO, buffer);

38. }

39.

40. }

41. }



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2020-05-09 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: