关于将状态机应用于嵌入式软件设计的问题
最近在南方老树的网站里看到了一些关于将状态机应用于嵌入式软件设计的问题的转帖也想谈些应用问题,自己也发表过I2C/TWI/USI实现状态机控制的实战例程:
I2C(TWI/SMBUS)LPC213X主机通讯例程
TWI一主多从实战程序片段
状态机在EDA中设计很普遍,有些甚至离不开它.
虽然在MCU设计中应用也很广,但有时即使可以也不得不放弃,这主要和MCU的众多因素有关.
不可否认,有时事例用状态机设计很简单,而且思路很清晰.
例如xf.zhu的状态机键盘扫描程序
但是在小容量程序空间的MCU中,可能菜农的"零耗时键盘"更能节省空间.
例如零耗时键盘各种事件及消抖处理模板裸奔程序详解
以菜农的倒塌思想去理解"状态机":
状态机就是我们预先编排的程序序列,我们设计的是如何诱导程序正常地进入此序列.
当程序不遵从序列(状态)时,将会引发错误的出现.
当程序遵从序列(状态)时,程序将根据此时的状态来安排下一步的状态(序列).
现在摘录菜农从未发表过的USI从机实战程序片段举例.
void UsiObj::Start(void)
{
set_sleep_mode(SLEEP_MODE_IDLE);
Status = 0;//状态初始化
USICR = (1 << USISIE) | (1 << USIOIE) | (1 << USIWM1) |(1 << USIWM0) |(1 << USICS1);// |(1 << USICS0);
USISR = 0xf0; //清除USISIF,USIOIF,USIPF,USIDC标志和设置计数器16次即接收1个字节8位(SCL上升及下降沿都计数)
DDRB &= ~(1 << SCL); //SCL设置为输入方式,SCL信号由主机提供
DDRB &= ~(1 << SDA); //SDA设置为输入方式
Count = 0;//数组指针计数器归零
}
因为在从机收到Start硬件信号后会产生中断,从机运行Usi.Start()函数.
进行状态机的初始化,即Status = 0;程序被逼迫下次中断进行芯片读写地址分析.
下次中断时运行:
void UsiObj::Exec(void)
{
unsigned char tmp;
Count &= 0x03;//防止数组溢出
/*-------------------------------------------------------------------
优化示例:
DDRB &= ~((1 << SCL) | (1 << SDA)); //SCL设置为输入方式,SCL信号由主机提供
上句将比下两句代码多编译2个字节
DDRB &= ~(1 << SCL); //SCL设置为输入方式,SCL信号由主机提供
DDRB &= ~(1 << SDA); //SDA设置为输入方式
--------------------------------------------------------------------*/
DDRB &= ~(1 << SCL); //SCL设置为输入方式,SCL信号由主机提供
DDRB &= ~(1 << SDA); //SDA设置为输入方式
/*-------------------------------------------------------------------
优化示例:
while (PINB & (1 << SCL));//等待SCL=0主机处理结束
上句将比下句代码多编译16个字节
while ((unsigned char)tmp = (PINB & (1 << SCL)));//等待SCL=0主机处理结束
--------------------------------------------------------------------*/
while ((tmp = (PINB & (1 << SCL))) != 0);//等待SCL=0主机处理结束
PORTB &= ~(1 << SCL);//保持低电平
DDRB |= (1 << SCL);//占用SCL总线,以便长期处理
switch(Status) {
case 0: //状态TW_START,从机地址判别
Address = USIDR;//取本机滚动地址0b0000000R/W~0b1111111R/W
Status = ((Address & 0x01) + 1);//Status下次主发为1W,主收为2R
Count = 0;//数组指针计数器归零
SendAck();
break;
case 1: //状态TW_MT_SLA_ACK,主发从收模式
Status = 3;//下次进入接收命令状态
USISR = 0x00; //准备接收8位命令
break;
case 2: //状态TW_MR_SLA_ACK或TW_MR_DATA_ACK,主收从发模式
Status = 4;
USIDR = TxBuffer ^ Address;//发送并加密8位数据1个字节
USISR = 0x00; //继续发送8位数据
DDRB |= (1 << SDA);//从机SDA需要输出数据,故设置为输出方式
break;
case 3: //状态主发从收模式(接收数据状态)
//....
因为I2C中断是有序的,即模块的状态是"有序"的,也可认为这是硬件状态机.
那么在软件状态机Status=0时,就必定要对应硬件状态TW_START.否则出错处理进入休眠;
在从机收到从机地址后,若地址的最低为D0=0(W)时,在发送ACK后下次进入主发从收模式Status=0+1=1
在从机收到从机地址后,若地址的最低为D0=1(R)时,在发送ACK后下次进入主收从发模式Status=1+1=2
依此类推,从机的接收程序被诱导入了我们实现安排好的圈套~~~
从状态图来看,它很像二叉树,故"搜索"即诱导程序序列很快,而且条理很清.
当然菜农恶搞的关于USI接口密文传送增加I2C模块拦截难度的问题就只能点到为止了~~~
否则菜农的菜碗就保不住了~~~ 这个帖子竟然没人顶。 倒塌了!
这么好的帖子竞没人顶?
帮顶!! . 学习学习 谢谢 哈哈,我就是这么裸奔的。 谢谢,才发现,顶啊 顶,纯路过 学习了 这段时间21ic上状态机是个热门 最近在搞IAR的visualSTATE,感觉开发挺方便的,就是不知道这个东西编出的程序效率怎么样。 这个做法不错,支持!! 谢谢
正在学习 在无操作系统的情况下,是偶喜欢的编程方式,呵呵!俺住西安碑林区,呵呵!菜农在西安哪块? 谢谢
正在学习 不顶不行 要顶呀 顶 嗯 个人风格不同 顶一个!! 顶!好东西!
按键处理,都是用状态机做的! MARK 状态机 学习IAR的visualSTATE 学习! 人工智能之父-----图灵想出来的 ,当然经典 mark 学习学习@! 这里让我了结 状态机。 支持,帮顶 状态机是好东西.
强贴留名,呵呵 ding 学习。 mark 学习, I2C从机只能采用状态机 看看! mark 留下脚印。。 mark! MARK ding! mark mark mark状态机 学习 mark ding!ding! mark 俺也用 学习一下! mark 零耗时键盘 状态机 mark 雁塔菜农 M0 顶顶~~~ mark mark mark 这个一定要mark 回复【10楼】igoal
最近在搞iar的visualstate,感觉开发挺方便的,就是不知道这个东西编出的程序效率怎么样。
-----------------------------------------------------------------------
我在学习过程中遇到很多问题,但不知道怎样解决。 下面是在网上搜到的一个针对状态机的简要总结:
“有限状态机系统优点:简单易用,状态间关系直观看到,便于编程;可以快速执行;只是通过改变输出功能来改变机器的响应。缺点:任何时刻系统只能有一个状态,无法表示并发性,不能描述异步并发系统;在系统部件多时,状态数随之增加,导致复杂性显著增长;对于大的应用系统,难于调试。 ”
感觉说的不够清楚,楼主能不能总结一下嵌入式中应用状态机的优缺点啊? 学习学习 深入浅出啊,讲的太好了--MARK!!!硬件状态机 状态机为什么这么火。。 学习一下 学习学习
页:
[1]