找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3339|回复: 7
收起左侧

RTX51tiny复杂应用---时钟、温度显示、按键解析 源程序

  [复制链接]
ID:79874 发表于 2020-2-2 19:23 | 显示全部楼层 |阅读模式
一、设计需求


在清翔51单片机开发板上,用带RTOS的方式实现下面的功能:


1. 板上有8个段码LED,左边的4个做一个计时器,显示“MSS.Z”,其中M为分钟,SS为秒,Z为n×0.1秒;右侧的4个,其中3个显示从18B20采集的实时温度,最后1个显示键盘的按键值,按键延时显示按键0.3秒(也就是松开按键之后还继续显示0.3秒);


2. 在板上的LCD1602上,构建一个HH:MM:SS 时分秒的钟表,同时将DS18B20的转换结果也显示在这里。


二、题目分析


面对一个复杂的题目,我们需要逐步实现需要的功能。先实现一个独立的功能,然后再增加功能,慢慢就能达到完整的要求。在实现独立功能的时候要考虑代码的可综合性,要尽量构建易于被调用的函数,在后期将会大大方面我们的综合优化。


编写代码的时候,尽量养成良好的习惯。对于一个庞大的工程,其必定可以分割为很多小模块。本题中用到了数码管、LCD1602、DS18B20、矩阵键盘这些外设,我们可以单独构建这些模块的驱动函数,后面再加以综合。


在创建好RTOS工程之后,在工程文件夹下再创建一个hardware文件夹,然后在这个文件夹里为每个外设都创建一个文件夹,如下图所示。






每一个外设都对应一个C文件和H文件,这两个文件放置在各自的文件夹中。这里还需要注意在keil中需要将这几个文件夹添加到编译路径中,要不然软件找不到H文件。在option中的incliude path处添加需要的路径。


做完这些准备工作后,我们就可以来分模块来构建我们的代码了。


三、模块分析


3.1 数码管


3.1.1 数码管显示函数


在使用的51开发板上,一共有8个数码管。这里我们可以编写一个函数,让其每一位可以单独显示任意数字。入口参数即为每一位要显示的数字,后面需要用到显示的地方,只需要传入对应的变量即可。比如构造如下的函数:


void play_SMG(unsigned char led7,led6,led5,led4,led3,led2,led1,led0);


在实际使用的时候,比如想让数码管显示1234567,就只需这样写:play_SMG(1,2,3,4,5,6,7)。一般我们都是要求数码管动态显示的,这时我们把对应的变量传入相应的位置即可。


函数内部的详细代码比较简单参见附录。


3.1.2 数码管闪烁问题


使用RTOS的时候,由于程序是轮循执行的。假如在一个任务中让数码管显示,就存在两个问题。


轮循时间间隔太短,数码管来不及全部显示。
任务数量太多,下一次显示间隔太长。
这里要搞清楚轮循的时间怎么计算。轮循时每个任务执行的时间是固定的,这个时间具体可以通过INT_CLOCK和TIMESHARING相乘得到。默认的INT_CLOCK = 10000,TIMESHARING = 5。也就是每个任务执行时间为50ms。


不光是数码管,每个任务在执行的时候都存在这个问题。在调试数码管的时候,会发现闪烁严重,就是上面两个因素的影响。相比之下,后者影响更大。假如有4个任务,按照默认的时间片设定,每次显示之后就要等待至少150ms。这个间隔内数码管是不显示的,就会看到数码管间歇性亮,或者很晃眼。


这时候可以通过更改时间片来获得比较好的显示效果。


3.2 时钟


3.2.1 产生时间基准


我们可以通过让数码管显示一个时钟来验证我们的函数正确性,同时这也是题目要求的一部分。


对于时钟的构建,可以先设定一个最小的时间基准,比如100ms,每个100ms对应的变量自加一次。10个100ms之后即1s的时候,代表秒的变量自加一次。当秒个位加到9的时候,十位加一,当59秒的时候再过1秒,秒清零同时分的个位加一……,这个过程写起来比较繁琐,需要细心不要搞错了。


这里的主要问题是怎么产生100ms的时间间隔。我们可以在一个任务中产生我们的时钟。100ms的间隔用延时函数来产生。


关于RTOS的延时,系统中给了os_wait2( ),这个函数有两个输入参数,详细可以看帮助文档。这里需要注意一个tick代表多长时间,这个可以在Conf_tny.51文件中查看,通过INT_CLOCK的值来计算,默认值为10000,如果使用12M的晶振,那么这里就是10ms,也就是说如果我们写了os_wait2( K_TMO,1),就是代表延时10ms。我们会发现这里最小的延时单位只能是10ms。可以更改INT_CLOCK的值来减小延时单位长度。这里我将INT_CLOCK的值改为了1000,那么一个延时单位就是1ms。需要注意,os_wait2( )中的参数类型是unsigned char,意味着我们最大只能写255,如果需要更长的延时,可以通过for循环来构建。


3.2.2 时钟显示


定义用来表示时钟的变量:uchar H1,H0,M1,M0,S1,S0,Z;


H、M、S分别为时分秒,Z为n×0.1秒。时钟的产生比较简单,就是需要的逻辑性比较强,详细的代码参见附录。


然后如下编写job0的代码:


void job0 (void) _task_ 0

{

    os_create_task (1);

    while (1)

    {

          play_SMG(M0,S1,S0,Z,0,0,0,0);     

    }

}
可以看到前四个数码管显示了计时器的值,后四个数码管一直显示0。这说明我们的代码是没有问题的。对于时钟的产生,这里采用了比较直观的方式去产生,易于理解,但是写起来需要注意代码的逻辑性。我们也可以尝试使用更简洁的方式去构建。


通过这个过程我们也可以发现代码的综合其实并不难,就是一步一步添加功能的过程。


3.3 键盘显示


3.3.1 矩阵键盘扫描


矩阵键盘扫描的函数有很多,它的原理网上也讲的很多,不再赘述。


很多时候我们要做的并不是自己如何去写一个器件的驱动程序,是如何把别人拿过来用。看懂别人的代码,可以改善并融合到自己的程序中是最好的。


假如现在手头有一个键盘扫描的代码,当检测到某个按键按下的时候会返回一个值,不同的按键按下有不同的返回值。该怎么将其加入到我们的代码中呢?


这里可以创建一个任务用来进行按键检测,并创建一个变量key用来表示按键值。通过不同的按键返回值来给key进行赋值。截取部分代码如下:


void keys (void) _task_ 3

{

    while (1)

    {

        switch( KeyScan() )

        {

            //第一行键值码

            case 0xee: key = 0;       break;

            case 0xde: key = 1;       break;

            case 0xbe: key = 2;       break;

            case 0x7e: key = 3;       break;

            ……

        }

    }

}
在任务三中key的值将根据按键的值改变。接下来我们只需要将按键的值送给数码管显示即可。play_SMG(M0,S1,S0,Z,0,0,0,key),将key放在数码管显示函数的最后一位。这样我们又完成了一个功能的添加,也没有改变程序原本运行的状态。


3.3.2 清除按键显示


在题目中要求按键延时显示按键0.3秒(也就是松开按键之后还继续显示0.3秒);也就是在手松开0.3秒之后要清除显示。


这里可以设置一个标志位flag,当按键按下的时候让flag置1,并且延时300ms后将flag清0。这样我们就可以通过flag的状态判断按键有没有按下,并且flag是滞后于手松开300ms刷新的。具体的代码如下:


unsigned char KeyScan() //带返回值的子函数

{

   unsigned char i;

      unsigned char cord_l,cord_h;//声明列线和行线的值的储存变量

      P3 = 0x0f;//0000 1111

      if( (P3 & 0x0f) != 0x0f)//判断是否有按键按下

      {

        os_wait2(K_TMO,5);//软件消抖

             if( (P3 & 0x0f) != 0x0f)//判断是否有按键按下

             {

                      cord_h = P3 & 0x0f;// 储存行线值

                      P3 = cord_l | 0xf0;

                      cord_l = P3 & 0xf0;// 储存列线值

            flag = 1;

            return (cord_l + cord_h);//返回键值码                    

             }   

      }

    if(flag)

    {

        for(i = 0; i < 3; i++)

        {


^^^^^
keil工程下载地址:
RTOS复杂应用.zip (100.71 KB, 下载次数: 108)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:65956 发表于 2020-2-4 21:13 | 显示全部楼层
我也曾在几个项目中用过,但没有这么复杂,就是要搞清逻辑就可以了,把各个要执行函数分配到任务中,注意任务时间的区别与错开,这样就不会冲突了

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:92004 发表于 2020-4-1 13:35 | 显示全部楼层
18b20中仍就用到了delay等待,没有用到 os_wait

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:902133 发表于 2021-5-23 00:06 | 显示全部楼层
我的IIC传感器效率较低,同时还要处理通讯需求,不指导可不可以用。
回复

使用道具 举报

ID:28992 发表于 2021-5-23 01:57 | 显示全部楼层
thank you sir!
回复

使用道具 举报

ID:929300 发表于 2021-5-29 22:55 | 显示全部楼层
18b20延时怎么保证数码管不闪
回复

使用道具 举报

ID:527324 发表于 2021-8-3 16:17 | 显示全部楼层
多任务读写25芯片咋弄啊
回复

使用道具 举报

ID:140644 发表于 2022-10-12 11:03 | 显示全部楼层
先下了看看,等一下试试能不能编译
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表