以前数电实验中有状态机控制系统工作状态变化的部分。虽然实验是基于FPGA,使用 Verilog 实现的,但是这可以为我使用C语言在NUCLEO单片机上实现状态机功能提供思路。其实开发语言并不重要,重要的是先做好状态机的设计,思考清楚状态数和状态转移条件。我使用两位的bool型数组status[2]记录系统状态。我设计的程序中单片机有四种工作状态,对应的二进制状态标号如下:
序号 | 系统状态 | 二进制状态编号 |
---|---|---|
1 | 快速呼吸灯 | 00b |
2 | 慢速呼吸灯 | 01b |
3 | 0.5Hz LED闪烁 | 10b |
4 | 2.5Hz LED闪烁 | 11b |
按键的下降沿触发状态转移函数(程序中的pressed)的执行,status[2]的值变化。由于主函数根据status[2]的值执行不同的程序,故系统的状态随之改变。这样实现了按下按键系统状态变化的功能。系统状态转移规律是:00->01->10->11->00.
状态转移图:
呼吸灯闪烁快慢可以通过改变占空比语句之间的延时语句的参数(延时时间)实现。可以结合条件状态判断改变延时时间,这样实现00和01对应的呼吸灯速度不同。
同理灯的闪烁是PWM占空比在1.0和0.0之间二值变化。通过判断状态改变延时时间可以改变灯的闪烁频率。
源代码:
#include "mbed.h"
InterruptIn my_button(USER_BUTTON);
DigitalOut my_led(LED1);
PwmOut my_pwm(PA_7);
bool status[2]={0,0}; //记录系统状态
void pressed(void) //state machine
{
bool jinwei = false;
if(status[0]==0) status[0]=1,jinwei=false;
else {
status[0]=0,jinwei=true;
}
if(jinwei == true) {
if(status[1]==1)
status[1]=0;
else status[1]=1;
}
}
int main()
{
my_button.fall(&pressed); //下降沿触发状态变化
float i = 0.5; //dc
bool flag = true;
float dc = 1.0;
int t=10; //change freq of breathing lamp
int delay = 200;//change freq of LED blinking
// Set PWM
my_pwm.period_ms(10);
while (1) {
my_led.write(PA_7);
if(status[1]==0) {
my_pwm.write(i);
if(flag){
i+=0.01;
if(i>=1.0) flag=false;
}
else {
i=i-0.01;
if(i<=0) flag=true;
}
if(status[0]==0) t=10; else t=20; //根据状态改变t,改变呼吸速度
wait_ms(t);
}
else {
my_pwm.write(dc);
if(dc == 1.0) dc=0.0;
else dc=1.0;
if(status[0]==0) delay=1000; //根据状态改变delay,改变灯的闪烁频率
else delay=200;
wait_ms(delay);
}
}
}