0、简述
单片机使用LPC1115,采用ucos-ii。
程序主要包括:1个主任务、3个功能任务,1个串口发送任务,1个状态指示灯任务,1个蜂鸣器任务。
功能任务就是实现机器主要功能的任务,与机器的应用场合有很大的关系,所以在此不做过分详细的说明。每个功能可以实现开启、暂停、结束等命令,实现方式在下面说明。
其它几个任务是辅助性的任务,为了更好地服务于机器功能的实现。
1、主任务
解析上位机的命令,并向任务发送命令。
主任务结构伪代码
1 | static uint8_t queue_func_insert(struct andrdata* andr) |
主任务处理流程:
①解析上位机命令
②判断分析,如果合适,将命令发送至任务,等待任务应答。
这样处理意在将各功能任务与上位机命令分离,各部分相互独立,减弱耦合。
③主任务根据任务的应答进行后续处理。
2、功能任务
功能任务用来实现各个具体的功能,虽然因任务的不同而有所变化,但处理流程基本一致。代码框架如下。
1 | /* |
在任务执行过程中,检查邮箱是否有数据到来:如果有,则分析具体动作,并执行之;否则就继续运行。命令包括几个方面:暂停(需要处理超时,不能长时间暂停)、恢复、停止(结束任务)等。
因不同任务有不同的特点,所以各个任务会有各自的处理细节。比如某个任务工作时,仅仅需要计时即可,当达到定时要求后结束执行即可。而另一个任务功能则需要计量液体体积,同时检测水桶的水位,如果水位低于警报值,那么需要提醒用户或者报警;另一方面,向水桶中注水时则需要关注高水位警报。
3、辅助任务
(1)串口发送任务
1 | void task_uart_send(void* pvData) |
在程序的不同位置会向串口发送数据,其实只是发送到队列,在这个任务中处理这些待发送的数据。结合实际的应用需求,单片机UART0通过扩展芯片外接有两个设备:上位机、Modbus设备。上位机是rs232接口,Modbus设备是rs485接口,并且Modbus设备是从设备,所以在处理Modbus设备时需要处理数据应答与重发问题。
可以这样简单理解。数据有多个源头,但是均需要从同一个串口发送,那么将他们放在一个队列中,在一个任务中将数据一个一个地取出并发送。在发送任务中,根据数据的不同目的设备,通过RS232或者RS485发送输出。

因为数据的接收也是从同一个uart进入,所以有可能丢失数据。比如在处理rs485设备时,rs232接口有数据过来,或者相反的情形。但是这种情况比较少,有几个原因:①上位机数据发送有比较大的时间间隔;②从rs485发送数据时是报警、开启停止任务的时候。但仍然存在数据丢失的可能性,所以才会有数据重发机制。
(2)状态指示与蜂鸣器
这里的处理与数据发送任务比较类似,数据来源于多个位置,但是均需要从同一个UART输出,所以使用队列的处理方式,在任务中从队列中取数据处理。
状态指示灯需要实现不同的效果,比如闪烁间隔、周期、次数等,各功能任务的状态显示均需通过状态指示任务处理,最后再通过串口发送任务发送数据。
还有一个报警功能。所谓的报警,就是通过状态指示灯与蜂鸣器来提醒用户,并且上位机在查询状态时,也会检查到报警状态并提示。
(3)空闲任务
电路板上有一个状态灯,将其放在空闲任务中,根据任务的不同状态,显示不同的状态。比如在空闲时为呼吸灯效果;有任务工作时,会是闪烁的状态;如果有报警,则以比较快的速度闪烁。
其实在各功能运行时,大部分时间都是阻塞的状态,所以空闲任务会运行大部分时间,将状态灯放在这里进一步减轻了主要任务的处理压力。
(4)其它细节
任务优先级
因为涉及到主任务与功能任务之间的通信以及串口数据发送问题,所以需要注意各个优先级的设置。在本项目中,功能任务优先级最高,主任务优先级次之,接着是串口发送任务,最后是蜂鸣器与状态指示任务。
同时工作的任务数量限制
这主要是实际应用的需求才这样设计,在上述代码中未体现。
一个问题是如何记录正在工作的任务及其数量?这里使用一个字节位的方式来处理。如果某个功能正在运行,那么将相应的位置1,完成后清0,统计1的数量就可以得到正在工作的任务的数量。
1
2
3
4
5
6
7
8
9
10static uint8_t get_bits_count(uint8_t data)
{
uint8_t i;
for(i = 0; data; i++)
{
data &= (data - 1) ;
}
return i;
}当然,单片机RAM有限,不可能同时运行太多的任务。
命令处理
指通信协议方面,需要做一些处理,包括命令的解析与数据打包,命令的应答等。同时,也要注意不同设备状态下命令的处理,比如:任务已经打开,不允许再次打开操作,否则返回错误命令等。
看门狗
采用外部看门狗芯片,放在主任务中处理,当然也还有其它处理方式,但是我理解不应该放在定时器中,因为有可能程序已经死机,但是定时器仍在运行,起不到应有的作用。
其它
报警的标记与清除、交易记录、参数设置、数据保存与读取(互斥量保护)等方面的内容。
4、问题
(1)RS485接口速度
板子的rs232与rs485从同一个uart引出,但是对于rs485接口,当波特率超过9600,数据收发就会出现错误,但是RS232即使波特率到了115200也是没有问题的。
板子与485设备均在机器内部,长度可能也就几十公分,在开发、测试时长度更短,并且总线上只有这一个485设备。
一个原因是板子的设计问题,另一个是接地问题,还可能是软件处理收发方向的问题。这个需要后续进一步地验证。
(2)液体计量精度
在管路上有一个编码器,通过统计编码器脉冲数可以计算得到流过的液体体积。当然精度不是很高,一是没有高精度的流量计,二是安装方式也会有很大的影响。因为并没有拿到一个产品的精确参数,只能通过多次测试来得到比较精确地参数。
当然,本产品也不需要很高的精度,否则就需要更高精度的物理实现了。
5、总结
本文从应用的角度总结了项目的软件结构,整个软件还包括上位机通信协议设计,这是很重要的一部分。其实这里的上位机就是一个运行Android系统的屏,安装在机器上作为用户操作的界面,与它的通信通过RS232进行,Android屏作为通信的发起者,这里的单片机程序接收数据并应答。
整个项目从软件的设计、开发调试,到最后的测试,这个过程中遇到了一些问题,还有一些很低级的错误。但是因为涉及到多个部门,所以需要耐心沟通,慢慢调试,找出问题并解决之。