第五章 节拍定时器.docx
- 文档编号:12121285
- 上传时间:2023-04-17
- 格式:DOCX
- 页数:19
- 大小:63.44KB
第五章 节拍定时器.docx
《第五章 节拍定时器.docx》由会员分享,可在线阅读,更多相关《第五章 节拍定时器.docx(19页珍藏版)》请在冰豆网上搜索。
第五章节拍定时器
第五章节拍定时器
5.1节拍定时器概述
STM32F10x内核中有一个节拍定时器。
节拍定时器为一个24位递减计数器,节拍定时器设定初值并使能后,每经过1个系统时钟周期,计数值就减1。
当计数值递减到0时,节拍定时器自动重装初值,并继续向下计数,同时内部的COUNTFLAG标志会置位,触发中断(如果中断使能)。
节拍定时器,其功能简单,只能提供一个节拍定时用,一般作为系统的嘀嗒。
在使用外部晶振为8MHz,9倍频,系统时钟为72MHz,节拍定时器的递减频率可以设为9MHz(如HCLK/8)。
在这个条件下,把系统定时器的初始值设置成90000,就能够产生10ms的时间基值,如果开启中断,则产生10ms的中断。
利用ST的函数库使用systick的方法
1、调用SysTick_CounterCmd()失能SysTick计数器
2、调用SysTick_ITConfig()失能SysTick中断
3、调用SysTick_CLKSourceConfig()设置SysTick时钟源。
4、调用SysTick_SetReload()设置SysTick重装载值。
5、调用SysTick_ITConfig() 使能SysTick中断
6、调用SysTick_CounterCmd()开启SysTick计数器
下面部分我们分别来介绍这几个库函数。
5.2库函数介绍
5.2.1函数SysTick_CLKSourceConfig
SysTick_CLKSourceConfig函数,其功能为设置SysTick时钟源。
表5-2-1.描述了函数SysTick_CLKSourceConfig
函数名
SysTick_CLKSourceConfig
函数原形
voidSysTick_CLKSourceConfig(u32SysTick_CLKSource)
功能描述
设置SysTick时钟源
输入参数
SysTick_CLKSource:
SysTick时钟源
输出参数
无
返回值
无
先决条件
无
被调用函数
无
表5-2-2列举了SysTick_CLKSource参数允许取值范围
表5-2-2SysTick_CLKSource值
SysTick_CLKSource参数可取的值
描述
SysTick_CLKSource_HCLK_Div8
SysTick时钟源为AHB时钟除以8
SysTick_CLKSource_HCLK
SysTick时钟源为AHB时钟
例:
设置系统定时器时钟为AHB时钟
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
5.2.2函数SysTick_SetReload
函数SysTick_SetReload的功能为设置SysTick重装载值。
表5-2-3描述了函数SysTick_SetReload
函数名
SysTick_SetReload
函数原形
voidSysTick_SetReload(u32Reload)
功能描述
设置SysTick重装载值
输入参数
Reload:
重装载值,该参数取值必须在1和0x00FFFFFF之间
输出参数
无
返回值
无
先决条件
无
被调用函数
无
例:
设定系统定时器的重载值为90000
SysTick_SetReload(90000);
5.2.3函数SysTick_CounterCmd
函数SysTick_CounterCmd的功能为使能或者失能SysTick计数器
表5-2-4.描述了函数SysTick_CounterCmd
函数名
SysTick_CounterCmd
函数原形
voidSysTick_CounterCmd(u32SysTick_Counter)
功能描述
使能或者失能SysTick计数器
输入参数
SysTick_Counter:
SysTick计数器新状态
输出参数
无
返回值
无
先决条件
无
被调用函数
无
表5-2-5列举了SysTick_Counter参数可取的值。
表5-2-5.SysTick_Counter值
SysTick_Counter参数可取的值
描述
SysTick_Counter_Disable
失能计数器
SysTick_Counter_Enable
使能计数器
SysTick_Counter_Clear
清除计数器值为0
例:
使能系统定时器
SysTick_CounterCmd(SysTick_Counter_Enable);
5.2.4函数SysTick_ITConfig
函数SysTick_ITConfig的功能是使能或者失能SysTick中断。
表5-2-6.描述了函数SysTick_ITConfig
函数名
SysTick_ITConfig
函数原形
voidSysTick_ITConfig(FunctionalStateNewState)
功能描述
使能或者失能SysTick中断
输入参数
NewState:
SysTick中断的新状态,这个参数可以取:
ENABLE或者DISABLE
输出参数
无
返回值
无
先决条件
无
被调用函数
无
例:
使能系统定时器中断
SysTick_ITConfig(ENABLE);
5.2.5函数SysTick_GetCounter
函数SysTick_GetCounter的功能是获取SysTick计数器的值。
表5-2-7描述了函数SysTick_GetCounter
函数名
SysTick_GetCounter
函数原形
u32SysTick_GetCounter(void)
功能描述
获取SysTick计数器的值
输入参数
无
输出参数
无
返回值
SysTick计数器的值
先决条件
无
被调用函数
无
例:
获取系统定时器的计数值
u32SysTickCurrentCounterValue;
SysTickCurrentCounterValue=SysTick_GetCounter();
5.3节拍定时器试验1—嘀嗒实例
5.3.1实验要求
利用节拍定时器,每10毫秒中断一次,每500毫秒跳变一次LED8。
5.3.2软件结构
在程序中,需要初始化节拍定时器,使节拍定时器每10ms重载一次,并开启节拍定时器中断。
在中断程序中,每进入一次中断,让一计数变量加1,然后判断是否有50次,如果有50次,则跳变一下LED8灯,同时把计数变量清0。
这样程序运行时LED8灯就不停地闪烁。
图5-3-1是程序的流程图。
图5-3-1软件流程图
5.3.3实例代码
以队列收发数据为基础,来进行添加。
首先创建E:
\OpenM3V开发板测试程序\SysTick\sys_delay文件夹,把E:
\OpenM3V开发板测试程序\USART\USART3文件夹中的工程,复制到E:
\OpenM3V开发板测试程序\SysTick\sys_delay文件夹中,,编译下载,看程序复制是否正确,这一步很关键,在作任何更改前,必须验证前一步的正确和完整性。
对其的态度是,宁愿认为其是错误的,也不要去假设它是正确的。
所有正确的东西,必须要实际测试后才能确定。
有时看似麻烦的东西,却能节省好多时间和精力,并给我们对下一步的信心。
验证通过后,点击
图标,在编辑对话框中出现一个新的空白文档,在这个文档中加入以下这部分内容,然后点击存盘,文件保存在本工程文件所在地文件夹中,命名为systic.c。
这个文件中,存放系统定时器初始化有关的所有程序代码和函数。
同时把这个文件加入到文件组USER中。
下面是systic.c文件中系统定时器初始化的程序清单:
#include"stm32f10x_lib.h"
unsignedcharsys_nub;//系统定时器中断计数变量
//SysTick设置
voidSysTick_Config(void)
{
//失能SysTick定时器
SysTick_CounterCmd(SysTick_Counter_Disable);
//失能SysTick中断
SysTick_ITConfig(DISABLE);
//设置SysTick时钟源
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
//设置SysTick重载值,10ms重载一次,在72Mhz时钟下
SysTick_SetReload(90000);
//开SysTick中断
SysTick_ITConfig(ENABLE);
//开SysTick定时器
SysTick_CounterCmd(SysTick_Counter_Enable);
}
点击
图标,在编辑对话框中出现一个新的空白文档,在这个文档中加入以下这部分内容,然后点击存盘,文件保存在本工程文件所在地文件夹中,命名为systic.h。
voidSysTick_Config(void);
externunsignedcharsys_nub;
在stm32f10x_it.c文件中,加入头函数systic.h,在系统中断定时器中断函数voidSysTickHandler(void)中加入以下程序代码:
voidSysTickHandler(void)
{
sys_nub++;//系统定时器中断计数变量加1
if(sys_nub>49)//计数到50时
{
sys_nub=0;//清0计数变量
LED8B();//跳转LED8灯
}
}
在主函数中加入头文件systic.h,并加入系统定时器初始化函数SysTick_Config()。
程序代码分析:
在main函数中,首先启动时钟和初始化嵌套向量中断控制器(NVIC),然后再调用I/O口、串口系统定时器初始化函数。
在系统定时器中断中计数中断次数,当达到50次时,跳转LED8灯。
5.3.4编译下载和调试
通过Project\RebuildAll命令进行编译。
编译通过后,在其工程文件夹下Debug\Exe目录下有一个.HEX后缀的文件,此为可执行文件,使用ST提供的下载工具,以ISP方式把程序下载到芯片中。
复位系统,可以看到LED8每秒钟闪烁一次。
打开串口调试助手,可以看到,PC机发送什么数据,串口也能接收到相同的数据。
5.4有实际应用意义的键盘实例
5.4.1实验要求
有了这个节拍定时器实验后,回过头来看前面的按键和串口还有LED灯,下面来做一个把三者结合起来的实验。
实验设计要求是,实现真正的按键功能,每按一次键,系统只识读一次,而不管按多长时间。
前面讲叙的按键识别没有进行防抖处理,在这里,使用系统定时器,来实现键盘防抖功能。
具体要求是:
每按K1键一次,LED1灯翻转一次,同时通过串口1发送0X31这个数据;每按K2键一次,LED2灯翻转一次,同时通过串口发送0X32这个数据;……每按K7键一次,LED7灯翻转一次,同时通过串口1发送0X37这个数据。
5.4.2软件结构
在这个键盘扫描程序的逻辑有点复杂,可以利用串口,把中间变量传出来,查看程序的流程和变量的值,方便调试,找出错误所在。
在这本书中,对于程序的调试,没有使用仿真器调试的方法,使用的是用LED灯指示程序的运行状态,用串口输出程序中的中间变量和过程变量。
这种方法,跟实际的运行结果一样,只是在最终版本中,把串口输出和LED指示部分注销就行,不必做任何的更改,同时能很好的观察到中断的运行情况,也能把程序运行的事件状况如实的表现出来。
由于stm32f10x系列的芯片的FLASH可以烧写上千次(现在的FLASH基本都能达到上千次的烧写),使得我们每次改动都能下载验证,而不必担心FLASH会很快烧坏。
这样对于学习单片机的费用就大大减少,不需要昂贵的仿真器,只需要一个根串口线就可以了。
回到这个实例上来,这个键盘处理逻辑比较复杂。
当一个键按下后,首先要判断是否有键按下,还要判断这个键是否处理过,还要判读是否延时过,只有经过这些判读处理后才能真正实现我们所要的功能。
图5-4-1是键盘扫描的流程图。
图5-4-1按键流程图
5.3.3实例代码
以嘀嗒实例为基础,来进行添加。
首先创建E:
\OpenM3V开发板测试程序\SysTick\key_usart文件夹,把E:
\OpenM3V开发板测试程序\SysTick\sys_delay文件夹中的工程,复制到E:
\OpenM3V开发板测试程序\SysTick\key_usart文件夹中,,编译下载验证,看程序复制是否正确,这一步很关键,在作任何更改前,必须验证前一步的正确和完整性。
在gpio.c文件中,加入键盘扫描函数和按键执行函数,具体函数如下:
voidkey1(void)
{
LED1B();
uart_trx[uart_rx]=0x31;
uart_rx++;
uart_rx&=0xf;
}
voidkey2(void)
{
LED2B();
uart_trx[uart_rx]=0x32;
uart_rx++;
uart_rx&=0xf;
}
voidkey3(void)
{
LED3B();
uart_trx[uart_rx]=0x33;
uart_rx++;
uart_rx&=0xf;
}
voidkey4(void)
{
LED4B();
uart_trx[uart_rx]=0x34;
uart_rx++;
uart_rx&=0xf;
}
voidkey5(void)
{
LED5B();
uart_trx[uart_rx]=0x35;
uart_rx++;
uart_rx&=0xf;
}
voidkey6(void)
{
LED6B();
uart_trx[uart_rx]=0x36;
uart_rx++;
uart_rx&=0xf;
}
voidkey7(void)
{
LED7B();
uart_trx[uart_rx]=0x37;
uart_rx++;
uart_rx&=0xf;
}
voidkey_work(void)
{unsignedcharkey_data;
key_data=GPIO_ReadInputData(GPIOE);//读取PE输入端口值
key_data&=0x7f
if(key_data<0x7F)//如果小于0X7F,说明有按键按下
{//LED2ON();//设置一个调试状态指示LED,有键按下亮。
if(!
(key_bit&0x02))//判断按键是否被处理,按键没有被处理,执行IF
{
if(key_bit&0x01)//如果已经延时了
{
key_bit&=~0x01;//清延时标志
key_bit|=0x02;//置位按键已处理标志
//uart_trx[uart_rx]=key_bit;//把标志变量功过串口传出来
//uart_rx++;
//uart_rx&=0x3f;
//uart_trx[uart_rx]=key_data;//把按键值通过串口传出来
//uart_rx++;
//uart_rx&=0x3f;
switch(key_data)
{
case0x7E:
key1();break;//调用key1()函数
case0x7D:
key2();break;//调用key2()函数
case0x7B:
key3();break;//调用key3()函数
case0x77:
key4();break;//调用key4()函数
case0x6F:
key5();break;//调用key5()函数
case0x5F:
key6();break;//调用key6()函数
case0x3F:
key7();break;//调用key7()函数
}
}
else//如果没有延时
{
key_bit|=0x04;//置位要延时标志
}
}
}
else//如果没有键按下,执行else
{
key_bit&=~0x07;//清所有的标志位
//LED2OFF();//无键按下LED灭。
}
}
在系统定时器中断中,加入相应的防抖程序代码,具体如下:
if(key_bit&0x04)//如果允许延时标志被置位的话
{
if(key_bit&0x80)//加入这个判断,只有当两次进入中断后才置位延时标志
{
key_bit|=0x01;//置位延时标志,表明经过延时
key_bit&=~0x04;//清允许延时标志位置位标志位
}
else//如果第7位没有置位,说明是第一次进入中断
{
key_bit|=0x80;//第一次进入时,把key_bit第7位置位。
}
}
在上面的程序中,加入了调试指示灯和中间变量输出部分。
里面有个非常关键的标志变量key_bit,在这个标志变量中,包含着许多信息,充分利用对不同位的判断来解析这些信息,为程序服务。
5.4.4编译下载和调试
通过Project\RebuildAll命令进行编译。
编译通过后,在其工程文件夹下Debug\Exe目录下有一个.HEX后缀的文件,此为可执行文件,使用ST提供的下载工具,以ISP方式把程序下载到芯片中。
复位系统,可以看到LED8每秒钟闪烁一次。
打开串口调试助手,可以看到,PC机发送什么数据,串口也能接收到相同的数据。
同时按K1键LED1灯跳变一次,同时串口有0X31数据输出(如果是ASC码方式,则输出为1),按其他键,则对应的LED等跳变,串口有相应的数据输出。
那么这个比较复杂的程序是不是一气写成的呢,答案是否定的。
下面把我写这个程序的过程向大家介绍一下。
把E:
\OpenM3V开发板测试程序\SysTick\sys_delay文件夹中的工程,复制到E:
\OpenM3V开发板测试程序\SysTick\key_usart文件夹中,下载到实验板中,灯是否闪烁,串口是否有数据输出。
由于需要用串口传出数据,所以串口功能的完善是必须保证的。
首先实现第一步目标是,有键按下时,LED1灯亮,松开时LED1灯灭,同时判断按键处理位,如果没有被处理,则让LED2跳转一次,并置位按键处理标志位。
这样只要按键被处理标志位置位就不会来跳转LED2灯,达到一次按键只处理一次的结果。
具体程序如下:
key_data=GPIO_ReadInputData(GPIOE);//读取PE输入端口值
key_data&=0x7f
if(key_data<0x7F)//如果小于0X7F,说明有按键按下
{
LED1ON();//LED1灯亮
if(!
(key_bit&0x02))//如果按键没有被处理
{
LED2B();//跳转LED2灯
key_bit|=0x02;//置按键处理标志
}
}
else
{
LED1OFF();//LED1灯灭
}
编译下载后,发现按下键后LED1灯亮,松手后就灭。
但不论按多少次,LED2灯就翻转一次。
程序哪里出问题了,很显然,程序没有执行if(!
(key_bit&0x02))语句下的内容,在这条语句前加上串口输出部分,把key_bit的值传出来看看,是什么内容。
加上以下语句。
uart_trx[uart_rx]=key_bit;//把数据写入串口队列中
uart_rx++;
uart_rx&=0x3f;
编译下载,打开串口调试软件,设置成38400,8,N,1,16进制显示,清空接收区域。
连接好串口线,打开实验板电源,按下任一键,可以看到串口出来一大串数据,LED1灯亮,LED2灯跳转一次,松开按键,LED1灯灭,串口也没有数据输出,在串口调试软件接收区,发现满篇都是0X02,我们找到数据头,发现第一个数据是0x00。
扫描多少次键盘,就有多少个串口数据输出。
我们把PC机上的串口调试软件的接收区域清零,然后再按一下任意键,当然LED1灯会亮,松手就灭,可LED2灯不跳转。
我们来看看输出的数据,全为0X02,找到第一个,也是0X02。
也就是说,在这次扫描过程中,按键程序把这次按下的键当作已经处理过。
问题出在哪,出在当松按键时,我们没有及时的清零按键处理标志位。
在else语句中加上以下这句就行了。
key_bit&=~0x02;//清零按键处理标志
编译下载,上面的BUG没有了,程序能按照我们设想去运行了。
在这里我们充分的利用了LED指示灯和中间变量的输出,来分析程序问题。
当然用仿真器单步或断点也会很快找出问题,只是仿真器调试的速度不一定有这里所介绍方法快。
首先我们使用LED2后,可以发现问题,同时可以判断程序错在哪,找出问题在哪,这就解决了一半的问题。
接下来,加入按键的延时防抖部分,思路是,利用系统定时器溢出间隔中断来延时防抖,这样就提高了程序的运行效率,不会在按键程序中死等20MS。
怎样才能很好的利用这个系统定时器来延时呢,如果只是简单在系统定时器中断中置位延时标志位的话,就没有任何意义。
必须得有一个标志位,来允许置延时标志。
第一次扫描到有按键按下时,延时标志肯定为空,那么我们在此置位一个标志位,来允许系统定时器中置位延时标志,这样就解决了这个问题。
软件的逻辑结构是:
如果没有延时,则置位允许延时标志置位标志(这句话有点拗口)。
可以这样理解,首先是置位标志位,那么这个标志位是干什么的呢,如果它置位的话,在系统定时器溢出中断中,就可以置位延时标志位,有点向指向指针的指针的意识。
如果已经延时,处理按键值。
下面这段程序加入了对延时标志判断的处理
if(!
(key_bit&0x02))//如果按键没有被处理
{
if(key_bit&0x01)//如果已经延时了
{
key_bit&=~0x01;//清延时标志位
LED2B();//跳转LED2灯
key_bit|=0x02;//置按键处理标志
}
else//如果没有被延时
{
key_bit|=0x04;//置位允许延时标志位置位标志位
}
}
系统定时器中断函数中加入这句话就行
if(key_bit&0x04)
{
key_bit|=0x01;//置位延时标志,表明经过延时
key_bit&=~0x04;//清
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第五章 节拍定时器 第五 节拍 定时器