1.2.3 定时器程序应用
了解了定时器相关的寄存器,那么我们下面就来做一个定时器的程序,巩固一下我们学到的内容。我们这节课的程序先使用定时器0,在使用定时器的时候,需要以下几个步骤:
第一步:设置特殊功能寄存器tmod,配置好工作模式;
第二步:设置计数寄存器th0和tl0的初值;
第三步:设置tcon,通过打开tr0位来让定时器开始计数。
第四步:判断tcon寄存器的tf0位,监测定时器溢出情况。
写程序之前,我们要先来学会计算如何用定时器定时时间。我们的晶振是11.0592m,时钟周期就是1/11059200,机器周期就是12/11059200,我们假如要定时20ms,就是0.02秒,要经过x个机器周期得到0.02秒,我们来算一下x*12/11059200=0.02,得到x= 18432。那么我们现在16位的定时器溢出值是65536,我们可以这样,先给th0和tl0一个初值,让他们经过18432个机器周期后刚好溢出,溢出后我们可以通过检测tf0位得知,就刚好是0.02秒。这个初值y = 65536 - 18432 = 47104,转成16进制就是0xb800,那么就是th0 = 0xb8,tl0 = 0x00。
那0.02秒我们已经定时出来了,细心的同学会发现,我们如果初值直接给一个0x0000,一直到65536溢出,定时器定时值最大也就是71ms左右,那么我们想定时更长时间怎么办呢?用你小学学过的逻辑,倍数关系就可以解决此问题。
那好了,我们下面就用程序来实现以下这个功能。
#include //包含寄存器的库文件
sbit led = p0^0;
sbit addr0 = p1^0;
sbit addr1 = p1^1;
sbit addr2 = p1^2;
sbit addr3 = p1^3;
sbit enled = p1^4;
void main()
{
unsigned char counter = 0;enled = 0; addr0 = 0; addr1 = 1;addr2 = 1; addr3 = 1; led = 1; //74hc138和led灯初始化部分tmod = 0x01; //设置定时器0为模式1th0 = 0xb8;tl0 = 0x00; //定时值初值tr0 = 1; //打开定时器0while(1){ if(1 == tf0) //判断定时器0是否溢出 { tf0 = 0; th0 = 0xb8; //一旦溢出后,重新赋值 tl0 = 0x00; counter++; if(50 == counter) //判断定时器0溢出是否达到50次 { counter = 0; //counter清0,重新计数 led = !led; //led取反操作,0-->1,1-->0 } } }}
程序都有注释,不难理解,这里要解释一个地方,就是两次if判断,细心的同学会发现,if(1 == tf0)这句,我把1写前边,这个地方我推荐新手按照我这样来写,因为如果我们写if(tf0 == 1),作为新手来说,不小心丢掉一个’=’号后,写成if(tf0 = 1),这样实际上在语法上是可以通过的,我们用的keil4还会出一个警告说明一下,keil以前的版本以及一些其他软件,可能根本不会出任何错误或者警告提示,但是这样产生的hex文件下载到单片机里边,程序就错了,大家可以改改试试看。
本程序实现的结果是我们板子上最右边的小灯点亮持续一秒,熄灭持续一秒,也就是以0.5hz的频率进行闪烁。
1.3 数码管学习
小灯是一种简单的led,给我们视觉效果只能通过亮和灭来表达简单信息。而这节课我们要来学习一种表达更加明确的器件,数码管。
1.3.1 数码管的基本介绍
先给大家提供一张原理图看一下,如图5-1所示。
图5-2 数码管原理图
这是比较常见的数码管的原理图,我们板子上一共有6只数码管。前边有了led小灯的学习,数码管学习就会轻松的多了。从图5-1能看出来,数码管共有a,b,c,d,e,f,g,dp这8个段,而实际上,这8个段每一段都是一个led小灯,所以数码管就是由8个led小灯所组成的。我们看一下数码管内部结构图5-2。
图5-3 数码管结构图
数码管分为共阳数码管和共阴数码管,所谓的共阴数码管就是8只led小灯的阴极是接在一起的,也就是阴极是公共端,由阳极来控制小灯是否亮灭。同理,共阳数码管就是阳极是接到一起的,大家可以仔细研究下图5-2。细心的同学也会发现,数码管上边有2个com,实际上就是我们数码管的公共端。为什么有2个,我个人认为,一方面有2个可以起到对称的效果,刚好是10个引脚,另外一个方面,公共端通过的电流较大,我们初中就学过,并联电路电流之和等于总电流,用2个com可以把公共电流平均到2个引脚上去,降低线路承受的电流。
从我们板子的电路图上能看出来,我们所用的数码管是共阳数码管,如图5-3所示。
图5-4 共阳数码管电路
他们的com是接到了正极上,当然了,和led小灯电路类似,也是由74hc138控制了三极管的导通来控制整个数码管的电流,我们先来看ds1这个数码管。原理图上可以看出来,控制ds1的三极管是q17,控制q17的引脚是leds0,对应到74hc138上边就是y0端的输出。
图5-5 74hc138控制图
我们现在的目的是让leds0这个引脚输出低电平,相信大家现在可以独立根据前边学到的内容把addr0,addr1,addr2,addr3,enled这4个输入状态写出来,现在大家不要偷懒,都去根据138的手册去写一下,不需要你记住这些结论,但是遇到就写一次,锻炼过几次后,遇到同类芯片自己就知道如何去解决问题了。
数码管通常是用来显示数字的,我们板子上的6个数码管,习惯上我们称之为6位,那控制位选择的就是74hc138了。而数码管内部的8个led小灯我们称之为数码管的段,那么数码管的段选择(即该段的亮灭)是通过p0口控制,经过74hc245驱动。
1.3.2 数码管的真值表
数码管的8个段,我们直接当成8个led小灯来控制,那就是a、b、c、d、e、f、g、dp一共8个led小灯。我们通过图5-1可以轻而易举的看出来,如果我们点亮b和c这两个led小灯,也就是数码管的b段和c段,其他的所有的段都熄灭的话,就可以让数码管ds1显示一个数字1,那么这个时候实际上p0的值的二进制就是0b11111001,十六进制就是0xf9。也有可以自动生成数码管段位码的软件可以从http://www.51hei.com/mcudown/ 下载文件名是数码管段位设码程序.rar,那么我们写一个程序进去,看看让数码管显示一下看看。
#include //包含寄存器的库文件 sbit addr0 = p1^0;sbit addr1 = p1^1;sbit addr2 = p1^2;sbit addr3 = p1^3;sbit enled = p1^4;void main(){ unsigned char j = 0; unsigned int i = 0; enled = 0; addr0 = 0; addr1 = 0; addr2 = 0; addr3 = 1; //74hc138开启三极管q17 while(1) //程序死循环 { p0 = 0xf9; //打开数码管b和c段 }}
大家把这个程序编译一下,下载到单片机里会发现,最右侧的数码管成功显示1这个数字。
同样的方法,我们可以把其他的数字都成功的在数码管上显示出来,而数码管显示的数字对应给p0的赋值,我们叫做数码管的真值表。我们来列一下我们这个电路图的数码管真值表,注意,这个真值表里显示的数字都不带小数点。
表5-1 数码管真值表
数字01234567
真值表 0xc0 0xf9 0xa4 0xb0 0x99 0x92 0x82 0xf8
数字 8 9 a b c d e f
真值表 0x80 0x90 0x88 0x83 0xc6 0xa1 0x86 0x8e
大家可以把上边那个数码管显示1的那个程序中的p0的赋值随便修改成我们表5-1中的真值表里的数字试试看,把数码管显示的数字显示出来。
1.3.3 数码管的静态显示
从第三课我们学习74hc138以后,我们了解到74hc138同时一次只能让一个输出口为低电平,也就是在一个时刻内,我们只能让一个数码管显示,始终选通数码管并且可以根据我们的p0总线的信号来改变这个数码管的值,我们可以理解为数码管的静态显示。
数码管静态显示是对应动态显示而言的,静态显示对于一两个数码管还行,多个数码管,静态显示实现的意义就没有了。这节课我们先用一个数码管的静态显示来实现一个简单的秒表,为下节课的动态显示打下基础。
先来介绍一个51单片机的关键字code。我们前边课程定义变量的时候,一般用到unsigned char或者unsigned int这两个关键字,这样定义的变量都是放在我们的单片机的ram中,我们在程序中可以随意去改变这个变量的值。但是还有一种常数,我们在程序中要使用,但是却不进行对这个值的改变,这种值我们可以加一个code关键字修饰一下,修饰完毕后,这个值就会存储到我们的程序空间flash中,这样可以大大节省我们单片机的ram的使用量,毕竟我们的ram空间比较小,而程序空间是很大的。比如我们现在要使用的数码管真值表,我们来看一下我们下边的这个程序。
#include //包含寄存器的库文件
sbit led = p0^0;
sbit addr0 = p1^0;
sbit addr1 = p1^1;
sbit addr2 = p1^2;
sbit addr3 = p1^3;
sbit enled = p1^4;
unsigned char code ledchar[] = {
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e}; //用数组来存储数码管真值表,下一课详细介绍数组
void main()
{
unsigned char counter = 0;unsigned char j = 0;enled = 0; addr0 = 0; addr1 = 0; addr2 = 0; addr3 = 1; p0 = 0xff; //74hc138和p0初始化部分 tmod = 0x01; //设置定时器0为模式1 th0 = 0xb8;tl0 = 0x00; //定时值初值 tr0 = 1; //打开定时器0while(1){ if(1 == tf0) //判断定时器0是否溢出 { tf0 = 0; th0 = 0xb8; //溢出后,重新赋值 tl0 = 0x00; counter++; if(50 == counter) //判断定时器0溢出是否达到50次 { counter = 0; //counter清0,重新计数 p0 = ledchar[j++]; //把数组里的对应值送给p0 if(16 == j) //当显示到f后,归0重新开始 { j = 0; } } }}}
虹科工业树莓派仅需4步实现传感器数据快速上云
酷暑炎热,必看这些智能家居解暑小技巧
emc整改计划与整改流程操作详解
35kv户外柱上真空断路器厂家技术知识分享
Linux中的ulimit命令详解
定时器和数码管解析(下)
AMD公司2018年营业额同比增长23% 获7年来最高利润率
FLIR T620便携式红外热像仪的性能特点及应用
CANOPEN协议连接器7/8-3芯4芯5芯连接器
美国海军电脑遭黑客入侵 超10万人敏感信息被窃
对2020年的中国锂电池市场进行了全面梳理
那些说用石墨烯做电池的企业,你扯真的?
LED路灯灯头的特点_LED路灯灯头的功能
Micro LED市场爆发期将至
提高MAX1737锂离子电池充电器的精度-Improving
三分钟使用HMI Board完成TCP ECHO服务器的搭建
GSM电力变压器防盗报警器简介
小米6评测:华为mate9标配和小米6第三方价格差不多了,你会选谁?
5G 中的 AFE 设计挑战解决方案
高性能的视频采集电路图