Прерывание по таймеру и прерывание приема UART
Я новичок в программировании, и мне трудно заставить прерывания работать так, как я хочу, для моего приложения. Я хочу отправлять последовательные данные через UART в PSoC, сохранять значения каждую секунду, а затем возвращать сохраненные значения. Я использую прерывание RX (FIFO RX не пусто, приоритет 2) и прерывание таймера с TC (приоритет 3). Прилагается конфигурация TopDesign. В настоящее время я пытаюсь заставить этот код работать (просто пример кода, чтобы посмотреть, смогу ли я заставить прерывания работать правильно). Я отправляю PSoC строку, содержащую символ "o", я должен читать только "o" и "-", но код всегда застревает в одном из прерываний, а другое никогда не работает. Может ли кто-нибудь сказать мне, что я делаю неправильно? Очень признателен! Плата является CY8CKIT-042.
#include <project.h>//Contains
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
uint16 ms_count = 0;
uint8 ch;
CY_ISR_PROTO(Timer_ISR);
CY_ISR_PROTO(RX_ISR);
CY_ISR(Timer_ISR){//Every millisecond, the code goes here
ms_count++;
if (ms_count == 1000){//Every second
ms_count = 0;
LED_Write(!LED_Read());
while(ch != 'o')UART_UartPutChar('-');
}
}
CY_ISR(RX_ISR){
uint8 status = UART_rx_ClearInterrupt();//Clear interrupt flag
uint8 sub;
sub = UART_UartGetChar();
if (sub != 0u){//Make sure grabbed character is not an empty
ch = sub;
if (ch == 'o'){
UART_UartPutChar(ch);
}
}
}
int main()
{
/* Start SCB UART TX+RX operation */
Timer_1_Start();
Time_ISR_StartEx(Timer_ISR);
RX_ISR_StartEx(RX_ISR);
CyGlobalIntEnable;
/* Start SCB UART TX+RX operation */
UART_Start();
UART_UartPutString("fdssf\n");
for(;;)
{
}
}
1 ответ
Я хочу отправлять последовательные данные через UART в PSoC, сохранять значения каждую секунду, а затем возвращать сохраненные значения. Я использую прерывание RX (FIFO RX не пусто, приоритет 2) и прерывание таймера с TC (приоритет 3).
Один важный принцип для процедур обработки прерываний (ISR) - сделать их как можно более короткими. Другой - убедиться, что они не блокируют. Как отметил Ханс Пассант в комментариях, ваш Timer_ISR блокируется с помощью цикла while. Это будет постоянно спам помещать символ "-" в UART и не позволять чему-либо еще происходить. Это плохая идея. ИМХО, включение вложенных прерываний не очень хорошая идея.
На самом деле, похоже, что вы уже повторяете символ 'o' в этой строке:
if (ch == 'o'){
UART_UartPutChar(ch);
}
Вы на самом деле не ждете секунду, чтобы повторить здесь "о", это происходит немедленно. Вы можете просто добавить UART_UartPutChar('-')
внутри этого if
Заявление также отправить черту сразу. Похоже, вы сейчас пишете простое тестовое приложение просто для того, чтобы все заработало, и я бы не стал ждать, пока не сработает таймер ISR, чтобы отобразить 'o' или '-' для простого тестового приложения.
В качестве альтернативы, если вы хотите печатать тире только раз в секунду, если буква "о" является последней прочитанной буквой, вы можете заменить while
петля с простым if
заявление:
if(ch == 'o')UART_UartPutChar('-');
Имейте в виду, что это сработало бы, только если 'o' был последним прочитанным символом, поскольку вы перезаписываете ch
переменная с каждым новым прочитанным символом (включая новые строки). Я не уверен, какой цели это послужит, но это так.
Что-то, что вы могли бы рассмотреть в будущем при использовании ISR - позволить ISR установить флаг и заставить основной цикл отслеживать этот флаг, а затем делать что-то, чтобы отреагировать на него, например:
int flag = 0;
CY_ISR(Timer_ISR){//Every millisecond, the code goes here
if (some event) {
flag=1;
}
void main() {
while (1) {
if (flag) {
flag=0;
do_something_in_a_long_loop();
}
}
}
Это только один из способов решения проблемы длинных петель. Кроме того, зависит ли ваше приложение от того, хотите ли вы сбросить флаг до или после длинного блока кода. Это имеет (очень вероятный) потенциал пропущенных событий, если ваш блок кода слишком длинный и события происходят слишком часто. В этом случае может быть хорошей идеей начать использовать потоки или операционные системы реального времени. То, как вы разрабатываете свою программу, очевидно, зависит от решаемой вами проблемы.
Предупреждение: при совместном использовании глобальных переменных между ISR и основным кодом или при работе с многопоточными приложениями очень легко столкнуться с условиями гонки. Вы должны знать об этих потенциальных подводных камнях и различных стратегиях правильного их устранения. Я бы посоветовал взять книгу или взять урок о встроенном программировании и / или операционных системах реального времени. Добро пожаловать в очень сложный мир встраивания и программирования в реальном времени!