PIC16F1937 和 UART:接收时保持 LED 亮起
PIC16F1937 and UART : keep led ON while receiving
我试图在 PIC 接收字符时(按下按钮时)保持 LED 亮起,默认情况下 LED 处于关闭状态,但我似乎找不到解决方案。
我用了 3 个月的时间学习使用微控制器(特别是 PIC)和 MPLABX IDE 编码,并开始了解 UART 通信。起初我尝试在收到字符时打开 LED ON/OFF,它运行良好并且工作正常,但现在我试图在按下按钮时保持 LED 处于活动状态但无法真正克服这个问题问题。我的代码在这样的中断函数中:
//#define LED RB5
void __interrupt () ISR (void)
{
if(RCIF) // data is received
{
data = RCREG; // get the value
if (data == '1') // if value received is '1'
LED = 1; //turn ON led
RCIF = 0;
}
LED = 0; // turn OFF led
}
使用上面的代码,当我一直按下按钮时,led 会 on/off 转得非常快,这并不是我想要的。
我希望有人能帮助我理解我的意思需要做。谢谢!
LED 熄灭很快,因为您在打开后立即关闭:
void __interrupt () ISR (void)
{
if(RCIF) // data is received
{
data = RCREG; // get the value
if (data == '1') // if value received is '1'
LED = 1; //turn ON led
RCIF = 0;
}
LED = 0; // turn OFF led <<=== This is executed unconditionally.
}
如果你不想每次都执行它,你可以将 LED = 0;
放在 else
分支中。
可能是这样的:
void __interrupt () ISR (void)
{
if(RCIF) // data is received
{
data = RCREG; // get the value
if (data == '1') // if value received is '1'
LED = 1; //turn ON led
else
LED = 0; // turn OFF led
RCIF = 0;
}
}
根据您的逻辑,else
可能会放在外部 if
块的末尾之后。
接收到任何字符后,LED 会迅速熄灭。
RCIF 标志只有在接收到 UART 数据时才会设置。因此,要关闭 LED,您应该启动一个特定毫秒的计时器,除非您的接收完成,否则请继续重新启动计时器。
void __interrupt () ISR (void)
{
if(RCIF) // data is received
{
data = RCREG; // get the value
if (data == '1') // if value received is '1'
LED = 1; //turn ON led
RCIF = 0;
start_timer_interrupt(x_ms); //set x_ms optimum timing so as to LED ON is visable with UART Rx
flag_rx_timer=1;
}
if(TIMER_OVERFLOW) //TIMER_OVERFLOW is an example keyword used here. Pleas add exact timer overflow flag
{
if(flag_rx_timer) //check if timer overflow is because of timer started during UART Rx
{
LED = 0;
flag_rx_timer=0;
}
}
}```
我建议您在 app.c 中为此创建一个状态机。
用 enum
和 struct
定义一些状态来保存状态并将它们放在 app.h 中,在您希望使用它的文件中包含 app.h
模块(例如您的 system_interrupt.c 文件)。
例如你可以这样做:
typedef enum{
IDLE,
START_RECEIVING,
STILL_RECEIVING,
}uart_state_t;
typedef struct{
uart_state_t current_state;
}uart_module_t
volatile uart_module_t uart_module = {0}; // initial state = IDLE, needs to be volatile because it will be updated via interrupt
然后创建一个函数来为您的状态机提供服务。这将处理它当前所处的状态并根据需要转换到其他状态。例如,状态机以 IDLE
状态开始,但是一旦您的中断被触发并且 RCIF
位被设置,那么您将转换到 START_RECEIVING
状态,这将打开 LED然后转换到 STILL_RECEIVING
状态,它将轮询 RCIF
位直到被清除。那看起来像这样:
void uartFSM(void){
switch(uart_module.current_state){
case IDLE:
{
break;
}
case START_RECEIVING:
{
LED = 1; // Turn LED on
uart_module.current_state = STILL_RECEIVING; // state update
break;
}
case STILL_RECEIVING:
{
if(!RCIF){
// done receiving
LED = 0; // Turn LED off
uart_module.current_state = IDLE; // state update
}
break;
}
default:
{
// whoops
break;
}
}
}
现在您的中断将如下所示:
void __interrupt () ISR (void)
{
if(RCIF) // data is received
{
data = RCREG; // get the value
// if value received is '1'
if (data == '1') uart_module.current_state = START_RECEIVING; // state update
}
}
现在您只需确保在 APP_Tasks
中的某个地方调用 uartFSM()
以便状态机得到服务。
我试图在 PIC 接收字符时(按下按钮时)保持 LED 亮起,默认情况下 LED 处于关闭状态,但我似乎找不到解决方案。
我用了 3 个月的时间学习使用微控制器(特别是 PIC)和 MPLABX IDE 编码,并开始了解 UART 通信。起初我尝试在收到字符时打开 LED ON/OFF,它运行良好并且工作正常,但现在我试图在按下按钮时保持 LED 处于活动状态但无法真正克服这个问题问题。我的代码在这样的中断函数中:
//#define LED RB5
void __interrupt () ISR (void)
{
if(RCIF) // data is received
{
data = RCREG; // get the value
if (data == '1') // if value received is '1'
LED = 1; //turn ON led
RCIF = 0;
}
LED = 0; // turn OFF led
}
使用上面的代码,当我一直按下按钮时,led 会 on/off 转得非常快,这并不是我想要的。
我希望有人能帮助我理解我的意思需要做。谢谢!
LED 熄灭很快,因为您在打开后立即关闭:
void __interrupt () ISR (void)
{
if(RCIF) // data is received
{
data = RCREG; // get the value
if (data == '1') // if value received is '1'
LED = 1; //turn ON led
RCIF = 0;
}
LED = 0; // turn OFF led <<=== This is executed unconditionally.
}
如果你不想每次都执行它,你可以将 LED = 0;
放在 else
分支中。
可能是这样的:
void __interrupt () ISR (void)
{
if(RCIF) // data is received
{
data = RCREG; // get the value
if (data == '1') // if value received is '1'
LED = 1; //turn ON led
else
LED = 0; // turn OFF led
RCIF = 0;
}
}
根据您的逻辑,else
可能会放在外部 if
块的末尾之后。
接收到任何字符后,LED 会迅速熄灭。 RCIF 标志只有在接收到 UART 数据时才会设置。因此,要关闭 LED,您应该启动一个特定毫秒的计时器,除非您的接收完成,否则请继续重新启动计时器。
void __interrupt () ISR (void)
{
if(RCIF) // data is received
{
data = RCREG; // get the value
if (data == '1') // if value received is '1'
LED = 1; //turn ON led
RCIF = 0;
start_timer_interrupt(x_ms); //set x_ms optimum timing so as to LED ON is visable with UART Rx
flag_rx_timer=1;
}
if(TIMER_OVERFLOW) //TIMER_OVERFLOW is an example keyword used here. Pleas add exact timer overflow flag
{
if(flag_rx_timer) //check if timer overflow is because of timer started during UART Rx
{
LED = 0;
flag_rx_timer=0;
}
}
}```
我建议您在 app.c 中为此创建一个状态机。
用 enum
和 struct
定义一些状态来保存状态并将它们放在 app.h 中,在您希望使用它的文件中包含 app.h
模块(例如您的 system_interrupt.c 文件)。
例如你可以这样做:
typedef enum{
IDLE,
START_RECEIVING,
STILL_RECEIVING,
}uart_state_t;
typedef struct{
uart_state_t current_state;
}uart_module_t
volatile uart_module_t uart_module = {0}; // initial state = IDLE, needs to be volatile because it will be updated via interrupt
然后创建一个函数来为您的状态机提供服务。这将处理它当前所处的状态并根据需要转换到其他状态。例如,状态机以 IDLE
状态开始,但是一旦您的中断被触发并且 RCIF
位被设置,那么您将转换到 START_RECEIVING
状态,这将打开 LED然后转换到 STILL_RECEIVING
状态,它将轮询 RCIF
位直到被清除。那看起来像这样:
void uartFSM(void){
switch(uart_module.current_state){
case IDLE:
{
break;
}
case START_RECEIVING:
{
LED = 1; // Turn LED on
uart_module.current_state = STILL_RECEIVING; // state update
break;
}
case STILL_RECEIVING:
{
if(!RCIF){
// done receiving
LED = 0; // Turn LED off
uart_module.current_state = IDLE; // state update
}
break;
}
default:
{
// whoops
break;
}
}
}
现在您的中断将如下所示:
void __interrupt () ISR (void)
{
if(RCIF) // data is received
{
data = RCREG; // get the value
// if value received is '1'
if (data == '1') uart_module.current_state = START_RECEIVING; // state update
}
}
现在您只需确保在 APP_Tasks
中的某个地方调用 uartFSM()
以便状态机得到服务。