Chinaunix首页 | 论坛 | 博客
  • 博客访问: 97436
  • 博文数量: 15
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 158
  • 用 户 组: 普通用户
  • 注册时间: 2015-01-29 17:33
文章存档

2016年(4)

2015年(11)

我的朋友

分类: 嵌入式

2015-04-08 13:29:21

本次设计选用的单片机是STCSTC15W402ASsop16封装。

1:首先单片机也属于嵌入式行业,当然它没有驱动那么复杂,也没有操作系统。但是简单不等于容易,没有了操作系统对于我们的限制,我们可以尽最大的能力去发挥硬件的优势,不同的单片机产品的功能,硬件架构可能不同,导致硬件参数不同,但软件上的操作大多类似,接下来我们看看单片机中要学习的几大重点吧!

 

2:时钟,对于当今的任何机器,只要它是按部就班的工作的它就需要时钟,就好像学校的铃声,没有规矩不成方圆,时钟是所有规矩的基础

Stc15系列单片机的时钟:

首先我们来看一看对于一个时钟,我们是怎样对它进行初始化,进行设置的呢?

程序如下(以time0为例,其他时钟类似)!

//********************* Timer0初始化函数************************/

void Timer0_Inilize(void)

{

TR0 = 0; //停止计数

EA  = 1;     //开放所有中断

ET0 = 1; //准许T0中断

PT0 = 0; //低优先级中断

TMOD = (TMOD & ~0x03);//16自动重装定时器

AUXR &= ~0x80; //定时器0是传统速度,12分频

INT_CLKO |=  0x01;//不准许p3.5管脚被配置为定时器0的时钟输出

TH0 = 0x94;//(u8)((65536UL - (MAIN_Fosc / 100UL)) >> 8);

TL0 = 0x00;//(u8)(65536UL - (MAIN_Fosc / 100UL));

TR0 = 1;//开始计数

}

 

/********************* Timer0中断函数************************/

//30ms 中断一次

//按住/释放0.6秒以下为无效操作,按住0.63秒为短按,3秒以上为长按,连按要求两次按下间隔不低于0.6秒不高于1.5

void timer0_int (void) interrupt TIMER0_VECTOR

{

//这里添加中断处理

}

接下来我们围绕单片机的时钟操作看看时钟到底是怎么成功运行的

首先声明各个寄存器的地址值都在头文件中进行声明,如:

//别问我0x88怎么来的,这里的地址都是从芯片手册中查到的

sfr TCON = 0x88;

sbit TR0  = TCON^4; //定时器0运行控制位

 

问:那么TCON这个寄存器时干什么的呢?

答:芯片手册上有,这里做一些简要介绍,TCON:定时器/计数器中断控制寄存器(可位寻址),这里的TR0:定时器T0的运行控制位,该位由软件置位和清零(该程序已经表明这一点),当GATE(TMOD.3) = 0TR0 = 1时就准许T0开始计数,TR0 = 0时就禁止T0计数,当GATE(TMOD.3) = 1TR0 = 1INT0输入高电平时,才准许T0计数,TR0 = 0 时禁止T0计数。

说到这里,应该懂得开始和结束的地方TR = 0, TR = 1是什么意思了吧,

你可能还会问:那GATE这个你没有设置啊!

回答:真的没有设置吗?我们来看看芯片手册


这就是GATE所在的位置,你发现什么了,对,它的复位值时00H,所以它就是0啊!当然如果你愿意也可以自己去设置,只是徒劳无功而已。那么GATE到底是什么作用呢?GATA:TMOD.3控制定时器0,置1时只有在INT0脚为高及TR0控制位置1时才可以打开定时器/计数器0.

当然我们这里的GATE0,所以不用关心INT0,但为了让你更加透彻,我还是来说说吧!

INT0:字面意思是外部中断,如果你学过操作系统,那你一定知道外部中断的意思了!简单而形象地说,就是硬件提供一个引脚,当这个引脚上有信号时,芯片正在执行的程序会停下来,转而去执行某个地址上的程序,执行完以后又回到原来的地方继续执行原来的程序,当然,有人不会理解为什么引脚有信号,原来的程序会停止,这个问题是由硬件完成的,学单片机的人了解原理即可,不需太较真。现在你已经懂得怎么开启关闭定时器/计数器了!

 

因为我们用的是定时器,所以我们还要把时间到了这样的信息告诉芯片,所以我们需要中断,当然不是上面的外部中断0,而是我们定时器自己自带的中断,所以接下来是ET0 的设置。

 

从手册上可以发现,这个字段属于IE寄存器

IE:中断准许寄存器

EA:CPU的总中断准许控制位,EA = 1CPU开放中断,EA = 0CPU屏蔽所有的中断请求。

EA的作用是使中断形成多级控制,即各中断源首先受EA控制,其次还受各中断源自己的中断准许控制位控制。

ET0T0的溢出中断准许位,ET0 = 1准许T0中断,ET0 = 0禁止T0中断

很明显:这里的作用就是打开大门在打开小门,这样中断信号就能进入芯片内部咯!

 

既然上面说到中断有优先级,那么我们的定时器的优先级是多少呢?接下来就是对T0优先级的设置:如下图可以看出PT0IP这个寄存器中。

IP:中断优先级控制寄存器

PT0:定时器0中断优先级控制位。

PT0 = 0时,定时器0中断为最低优先级中断(优先级0

PT0 = 1时,定时器0中断为最高优先级中断(优先级1

为了体验单片机的实时性,我们这里用到了最高优先级,即优先级1PT0 = 1

 

 

现在定时器/计数器打开,中断打开,优先级设置好,可是我们到底用的是定时器还是计数器呢?接下来我们设置的模式寄存器就可以解决这一点。

 

TMOD:定时器/计数器工作模式寄存器(这个寄存器有点复杂)

TMOD.7(GATE):控制定时器1,置1时只有在INT1脚为高及TR1控制位置1时 才可以打开定时器/计数器1。

TMOD.3(GATE):控制定时器0,置1时只有在INT0脚为高及TR0控制位置1时 才可以打开定时器/计数器1。

TMOD.6(C/T) : 控制定时器1用作定时器或计数器清0则用作定时器(对内部系 统时钟进行技术),置1用作计数器(对引脚T1/P3.5外部脉冲 进行计数)

TMOD.2(C/T): 控制定时器0用作定时器或计数器清0则用作定时器(对内部系 统时钟进行技术),置1用作计数器(对引脚T1/P3.4外部脉冲 进行计数)

TMOD.5/TMOD.4(M1,M0):定时器/计数器1模式选择

0 0 :16位自动重装定时器,当溢出时将RL_TH1和RL_TL1   存放的值自动重装如TH1和TL1中

0 1 :16位不可重装载模式,TL1,TH1全用

1 0 :8位自动重装载定时器,当溢出时将TH1存放的值自   动重装入TL1

1 1 : 定时器/计数器1此时无效(停止计数)

TMOD.1/TMOD.0(M1,M0):定时器/计数器0模式选择

0 0 :16位自动重装定时器,当溢出时将RL_TH0和RL_TL0   存放的值自动重装如TH0和TL0中

0 1 :16位不可重装载模式,TL0,TH0全用

1 0 :8位自动重装载定时器,当溢出时将TH1存放的值自   动重装入TL0

1 1 : 定时器/计数器0此时无效(停止计数)

接下来我们回到程序,

TMOD = (TMOD & ~0x03);//16自动重装定时器

这句话的意思就是将TMOD的最低2位置0,其余为保持不变(如果你不知道&~这些符号的意思,你可以去搬砖头了),对照上面写的就可以知道它为16位自动重装定时器。

 

现在我们又确定了模式,可是有个很重要的问题没有解决,那就是到底多少次计数是1ms呢?或者说我们的定时器的频率是多少呢?当然这里的频率指的是每秒多少次,

现在我就来带大家看看怎么设置频率!

 

AUXR寄存器的篇幅较长,请大家自己参考芯片手册去看,这里省略

AUXR &= ~0x80; //定时器0是传统速度,12分频

由表达式可知,AUXR的第7位被置0,其余位不变,即T0x12被置0

T0x12:定时器0速度控制位

0:定时器0是传统8051速度,12分频

1:定时器0的速度是传统805112倍,不分频




INT_CLKO:外部中断准许和时钟寄存器(具体请查看芯片手册)

INT_CLKO |=  0x01;//不准许p3.5管脚被配置为定时器0的时钟输出

即将最低为置位1T0CLKO  = 1;

T0CLKO:是否准许将P3.5/T1脚配置为定时器0T0)的时钟输出T0CLKO

1 :将P3.5/T1管脚配置为定时器0的时钟输出T0CLKO,输出时钟频率 = T0溢出率/2

    若定时器/计数器T0工作在定时器模式016位自动重装载模式)时,

    如果C/T = 0,定时器计数器T0是内部系统时钟计数,则:

T0工作在1T模式(AUXR.7/T0x12 = 1)时的输出频率 SYSclk/(65536 -[RL_TH0,RL_TL0])/2

T0工作在12T模式(AUXR.7/T0x12 = 0)时的输出频率 =SYSclk/12/(65536 - [RL_TH0,RL_TL0])/2

  如果C/T = 1,定时器/计数器T0是对外部脉冲(P3.4/T0)输入计数,则:

输出时钟频率 T0_Pin_CLK/(65536-[RL_TH0,RL_TL0])/2

若定时器/计数器T0工作在定时器模式28位自动重装模式),

如果C/T = 0,定时器/计数器T0是对内部系统时钟计数,则:

T0工作在1T模式(AUXR.7/T0x12 = 1)时的输出频率 SYSclk/(256 - TH0)/2

T0工作在12T模式(AUXR.7/T0x12 = 1)时的输出频率 SYSclk/12/(256 - TH0)/2

如果C/T = 1,定时器/计数器T0是对外部脉冲输入(P3.4/T0)计数,则:

输出时钟频率 T0_pin_clk/(256-TH0)/2

0 不准许P3.5/T1管脚被配置为定时器0的时钟输出

 

由此可见我们的任务也完成百分之九十了!接下来是怎么设置定时时间,1ms1min1year?当然一年就有点过于忽悠了!那怎么设置时间呢?上面说过定时值放在TH0TH1中。

 

 

TH0 = 0x94;//(u8)((65536UL - (MAIN_Fosc / 100UL)) >> 8);

TL0 = 0x00;//(u8)(65536UL - (MAIN_Fosc / 100UL));

问:65536UL - (MAIN_Fosc / 100UL是什么意思,为什么这么写?

答:我们的定时器不可能永远不停地去计数,那样的话总数会越来越大,达到一定数目就会溢出,假如我们的计数寄存器只有8位,那最大计数就是256,当然这里我们的溢出计数是65536,所以自然是16位了!那为什么这样运算呢?我们假设你的定时只有30ms而定时器的定时是65536ms,你怎么办。也许你会说,给他一个初始值65536-30,对了,这里就是这个意思,至于为什么要左移8位,那是因为TH0TL1只有8位不够存放,所以分开存放咯!

 

好了,万事俱备只欠东风,那定时器时间到了怎么办?在哪进行相应的处理呢?

没错,还是中断,前面我们设置了中断,就是为了现在的运用

第二个函数就是个中断函数

void timer0_int (void) interrupt TIMER0_VECTOR

void timer0_int (void) :这是中断函数的函数名

Interrupt :这是单片机特有的关键字,用来说明它修饰的函数是中断函数

TIMER0_VECTOR :这是一个中断向量。前面说过,发生中断会出现一个信号,中断向    量就是用来发现这个信号的。

至此,我们的定时器的程序写完了!由于个人能力有限,里面难免有些错误,还请各位及时纠正,

         学高为师,就到这里,谢谢各位!

 

 

 

阅读(9281) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:最简单的GPIO点灯驱动

给主人留下些什么吧!~~