完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
一、设计需求
设单片机的时钟12MHz,型号为AT89S52。单片机引脚连接有4个LED,其中:
题目中4个LED需要“同时”执行不同的操作,如果使用常规的方式来构建,是有一些难度的;而如果用RTX51 tiny,实现起来将比较简单。我们只需要构建不同的task,每一个task都相当于在单独执行,但是宏观上看起来多个任务是在 “同时”执行的,根据题目要求,除了简单的创建task,我们还需要用到task之间的信号传递。对于rtos的理解有点类似于数码管,快速依次去点亮每一位数码管,这显然是串行的操作,但是看起来这几位数码管是同时亮起来的,又像是在并行工作。 三、模块分析 3.1点亮LED1 题目要求LED1以30Hz的固定频率闪烁,经过计算可知LED1的电平状态需要33ms翻转一次。创建一个task,在这个task里每延时33ms让LED1电平翻转一次即可。 关于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循环来构建。 对LED1操作的代码如下: void LED1_CTRL (void) _task_ 1 { while (1) { os_wait2(K_TMO,33); LED1 = !LED1; } } 将程序下载到开发板中,可以看到LED1在快速闪烁。 3.2外部中断配置 LED2需要在外部中断发生以后,亮0.2秒,然后熄灭;这里需要用到按键来触发外部中断。在我们的开发板上有一个连接到P2^3引脚的按键,P2^3刚好是51单片机的外部中断引脚,我们可以对其进行配置来完成这个要求。 外部中断的配置比较简单,只需令EX0 = 1; IT0 = 1。EX0是外部中断0的使能控制位,IT0控制的是外部中断0的触发方式。IT0=0时,低电平触发;IT0=1时,后沿触发。 涉及到按键,就必须考虑到消抖的问题,在中断服务程序中进行消抖。当检测到中断发生之后,延时20ms再次检测按键的状态,如果这时按键依然处于按下的状态,就说明按键确实按下了。 void inter() interrupt 0 { os_wait2(K_TMO,20); if(key == 0) { key_flag = 1; } } 这里的key_flag是按键按下标志位。我们可以创建一个task,对key_flag的状态进行检测,如果检测到key_flag的电平为1,则点亮LED2,延时200ms后关闭LED2,并将key_flag的状态变为0。 将程序下载到开发板,可以看到当我们按下按键的时候,LED2会短暂的亮一下后熄灭,符合我们的要求。 3.3任务间信号传递 LED3需要在LED2熄灭以后以20Hz的频率闪烁10次然后熄灭;LED2和LED3在两个不同的task中,但是却有所关联,这就需要我们在两个task之间传递信息。 在LED3的task中等待信号,当有信号时执行20Hz的频率闪烁10次然后熄灭的操作;在LED2的task中添加一句当LED2熄灭后发出信号到LED3所在任务的代码即可。详细代码参见附录。 将程序下载到开发板,可以看到当我们按下按键后,LED2短暂的亮一下后熄灭,之后LED3以20Hz的频率闪烁10次后熄灭,符合设计要求。 3.4串口信息输出 所谓的串口其实就是一种通讯方式,通讯方式有很多种,像IIC、SPI这些都是常见的通讯方式。不同的通讯方式需要遵循不同的协议,就像是A给B发了一段密文,B必须知道相应的规则才能进行解析,不然就不能正常交流了。 数字逻辑只有0和1两种状态,当我们用特定的时序将0或1发送出去,就能传递一些信息,所以时序是我们需要特别注意的东西。串口最重要的是波特率的配置,单片机的串口需要用到定时器,主要就是用来产生特定的波特率。不同的波特率对应着不同的定时参数,定时器工作模式的不同也会影响参数的计算。由于RTOS已经占用了定时器0,所以这里用定时器1来对串口进行配置。 本实验中需要将LED的亮灭情况实时通过串口输出,需要注意LED状态是是在实时变化的,而我们知道串口发送一次数据是需要时间的,如果在发送数据的时候LED的状态发生了改变,当下一次发送的时候就会漏掉一些数据。这个问题就是两者的时间不同步造成的,在进行数据处理的时候我们经常会遇到这种情况。 为了解决这个问题,我们需要创建一个缓冲区(简单的做法是创建一个比较大的数组),LED的状态不停的写入到缓冲区中,由于对缓冲区的写入速度是很快的,所以我们不用担心数据会丢失。然后我们依次将缓冲区中的数据用串口发送出去,相当于一个栈,遵循先进先出的原则。虽然LED的变化速度和串口的发送速度存在差异,但是由于缓冲区的存在,我们不必担心数据会丢失。 由于缓冲区的代码实现上难度较大,所以没有深入去做,只实现了对串口的配置,然后在一个任务中持续打印P1端口的电平状态(LED连接在P1口),无疑这种方式数据丢失很严重。 代码下载到开发板后打开串口助手,可以看到单片机在持续发送P1的状态到PC。 四、总体方案设计 本实验借助了RTOS来实现,一定程度上减小了我们的设计难度,因为每一个task我们都可以单独去编写而几乎不用考虑别的模块。按照题目的要求依次去创建task,然后编写相应的操作逻辑即可。 五、总结 就题目而言,本次实验的难度是比较小的,但是通过简单的问题能更容易的去理解RTX51 tiny的运行方式。通过这次试验我们掌握了RTSO的基本操作,下一次遇到需要多任务并行的问题,我们便不会慌张了,不就是把对LED的操作换成了其它东西吗;同时对于task之间的信息传递也有了认识。 在解决问题的过程中,我们记住的肯定不是详细的代码,最终留下来的只有思考问题的能力。当我们学会去思考问题,不管是简单的还是复杂的任务,我们都能按部就班的去完成。 六、附完整代码 #include #include #include volatile unsigned char sending; ***it LED0 = P1^0; ***it LED1 = P1^1; ***it LED2 = P1^2; ***it LED3 = P1^3; ***it key = P3^2; bit key_flag; void uart_init() { TMOD&=0x0F; //定时器1模式控制在高4位 TMOD|=0x20; //定时器1工作在模式2,自动重装模式 SCON=0x50; //串口工作在模式1 TH1=0xFA; //计算定时器重装值 TL1=0xFA; PCON|=0x80; //串口波特率加倍 ES=1; //串行中断允许 TR1=1; //启动定时器1 REN=1; //允许接收 } void send(unsigned char d) //发送一个字节的数据,形参d即为待发送数据。 { SBUF=d; //将数据写入到串口缓冲 sending=1; //设置发送标志 while(sending); //等待发送完毕 } void job0 (void) _task_ 0 { EA = 0; EX0 = 1; IT0 = 1; uart_init(); EA = 1; os_create_task (1); os_create_task (2); os_create_task (3); while (1) { send(P1); } } void LED1_CTRL (void) _task_ 1 { while (1) { os_wait2(K_TMO,33); LED1 = !LED1; } } void LED2_CTRL (void) _task_ 2 { while (1) { if(key_flag) { LED2 = 0; os_wait2(K_TMO,200); LED2 = 1; key_flag = 0; isr_send_signal (3); } } } void LED3_CTRL (void) _task_ 3 { char i; while (1) { os_wait(K_SIG,0,0); for(i=0; i<20; i++) { os_wait2(K_TMO,50); LED3 = !LED3; } } } void inter() interrupt 0 { os_wait2(K_TMO,20); if(key == 0) { key_flag = 1; } } void uart(void) interrupt 4 //串口发送中断 { if(RI) //收到数据 { RI=0; //清中断请求 } else //发送完一字节数据 { TI=0; sending=0; //清正在发送标志 } } |
|
|
|
只有小组成员才能发言,加入小组>>
3316 浏览 9 评论
2995 浏览 16 评论
3494 浏览 1 评论
9060 浏览 16 评论
4088 浏览 18 评论
1180浏览 3评论
608浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
600浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2335浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1896浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-24 15:33 , Processed in 1.231114 second(s), Total 77, Slave 58 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号