stm8s的c语言编程例程应用

更新时间:2024-04-04 13:50:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

实例一:控制灯的亮灭(或者蜂鸣器响,只要连接相应端口就可以了): #include \头文件 #define ulong unsigned long

/////////////////////////////////////////////////////////////////////////////// void delay(ulong i) {ulong j;

for(j=0;j

}////////////延时函数

void main(void)////////////主函数 {

GPIO_DeInit(GPIOD);

GPIO_Init(GPIOD, GPIO_PIN_1, GPIO_MODE_OUT_PP_LOW_FAST); while(1) {

GPIO_WriteHigh(GPIOD, GPIO_PIN_1); delay(10000); delay(10000); delay(10000);

GPIO_WriteLow(GPIOD, GPIO_PIN_1); delay(10000); delay(10000); delay(10000); } }

第二步:控制灯按照一定的频率闪烁:频率可以使用时钟! Stm8启动时,主时钟默认为HSIRC时钟的8分频,HSIRC是可以提供一个低成本的16MHz时钟源,

#include \头文件 void CLK_Configuration(void); void main(void)////////////主函数 {

GPIO_DeInit(GPIOD);

GPIO_Init(GPIOD, GPIO_PIN_1, GPIO_MODE_OUT_PP_LOW_FAST); CLK_Configuration(); while(1) {

GPIO_WriteReverse(GPIOD, GPIO_PIN_1); } }

void CLK_Configuration(void) {

/* Fmaster = 16MHz */

CLK_HSIPrescalerConfig( CLK_PRESCALER_HISDIV1); }

例题三:灯闪亮的同时蜂鸣器响 #include \头文件 #define ulong unsigned long

/////////////////////////////////////////////////////////////////////////////// void delay(ulong i) {ulong j;

for(j=0;j

}////////////延时函数);

void main(void)////////////主函数 {

GPIO_DeInit(GPIOD); GPIO_DeInit(GPIOB);

GPIO_Init(GPIOD, GPIO_PIN_1, GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(GPIOB, GPIO_PIN_0,GPIO_MODE_OUT_PP_LOW_FAST ); while(1) {

GPIO_WriteHigh(GPIOD, GPIO_PIN_1); delay(10000); delay(10000);

GPIO_WriteLow(GPIOD, GPIO_PIN_1); delay(10000); delay(10000);

GPIO_WriteHigh(GPIOB, GPIO_PIN_0); delay(10000); delay(10000);

GPIO_WriteLow(GPIOB, GPIO_PIN_0); delay(10000); delay(10000); } }

时钟控制器功能强大而且灵活易用。其目的在于使用用户在获得最好性能的同时,亦能保证消耗的功率最低。

用户可以独立管理各个时钟源,并将它们分配到CPU或者各个外设。主时钟和CPU的时钟均带有分频器。 主时钟源:

四种时钟源可以作为主时钟源:

1.1—24MHz高速外部晶体振荡器(HSE)

2.最大24MHz高速外部时钟信号(HSE user-ext) 3.16MHz高速内部RC振荡器(HSI) 4.128KHz低速内部RC(LSI)

各个时钟源可独立打开或者关闭,从而优化功耗。

HSE:高速外部时钟信号,由两个时钟源产生:HSE外部晶体/陶瓷谐振器;HSE用户外部有源时钟。(为了最大限度的减少输出失真和减少启动失真的稳定时间,谐振器和负载电容应尽可能的靠近谐振器引脚。负载电容值应根据所选的谐振器进行调整。)

外部1至24MHz的振荡器其优点在于能够产生精确的占空比为50%的主时钟信号。 为使系统快速启动,复位后时钟控制器自动使用HSI的8分频(HSI/8)做为主时钟。其原因为HSI的稳定时间短,而8分频可保证系统在较差的VDD条件下安全启动。 时钟设置的目的到底是什么?时钟设置肯定会出现中断?

貌似是这样的:运用合适的时钟配置可以使得功耗降低,有时候计数频率很大,需要很大的计数或者怎么样时,需要使用其他的时钟,即非默认的时钟!暂且这样解释!

例题四:利用中断

按键控制灯的亮灭。

#include \头文件 void main(void)////////////主函数 {

GPIO_DeInit(GPIOD); GPIO_DeInit(GPIOB);

GPIO_Init(GPIOD, GPIO_PIN_1, GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(GPIOB, GPIO_PIN_0, GPIO_MODE_IN_FL_IT); EXTI_DeInit();

EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOB ,

EXTI_SENSITIVITY_FALL_ONLY );///////定义端口的外部中断

enableInterrupts();//////////////////这个一定不能丢,中断使能 while(1) { } }

#pragma vector=6//中断编号+2

__interrupt void EXIT_PORTB_IRQHander(void) {

if((GPIO_ReadInputData(GPIOB)&GPIO_PIN_0)==0x00)/////检查是否按下 {

GPIO_WriteReverse(GPIOD,GPIO_PIN_1); }

}

//////默认的时钟为HSI的8分频,即上电默认的频率。

中断设置为上升沿触发:则程序会有微小的变化: #include \头文件 void main(void)////////////主函数 {

GPIO_DeInit(GPIOD); GPIO_DeInit(GPIOB);

GPIO_Init(GPIOD, GPIO_PIN_1, GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(GPIOB, GPIO_PIN_0, GPIO_MODE_IN_FL_IT); EXTI_DeInit();

EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOB ,EXTI_SENSITIVITY_RISE_ONLY );///////定义端口的外部中断

enableInterrupts();//////////////////这个一定不能丢,中断使能 while(1) { } }

#pragma vector=6//中断编号+2

__interrupt void EXIT_PORTB_IRQHander(void) {

if((GPIO_ReadInputData(GPIOB)&GPIO_PIN_0)==0x01)/////检查是否按下 {

GPIO_WriteReverse(GPIOD,GPIO_PIN_1); } }

时钟这里到底是怎么回事啊?LSI等如何配置,配置时钟做什么用的?

例题五:设计一个程序使得当按键按下后发光二极管按照不同的频率闪烁。 分析:不同的频率闪烁,可以设置为按照100,500,1000,2000Hz的频率闪烁。

定时器timer4的使用:

该定时器由一个带可编程预分频器的8位可位自动重载的向上计数器所组成,它可以用来做时基发生器,具有溢出中断功能。

Timer6同时钟/触发信号控制器一起用于定时器同步和级联。

Time4的主要功能包括:

1.8位向上计数的自动重载计数器(既然是向上计数,那么计算初值时?) 2.3位可编程的与分配器(可在运行中修改),提供1,2,4,8,16,32,64,和128这8种分频比例。 3.中断产生

——在计数器更新时:计数器溢出。 Timer6的主要功能:

1.8位向上计数的自动重载计数器 2.3位可编程的与分配器(可在运行中修改),提供1,2,4,8,16,32,64,和128这8种分频比例。 3.用于和外部信号相连和定时器级联的同步电路 4.中断产生:

——在计数器更新时:计数器溢出 ——在触发信号输入时。 Timer4和timer6中断:

该定时器的时钟源是内部时钟(Fmaster)。该时钟源是直接连接到CK_PSC时钟的,CK_PSC时钟通过预分频器分频后给定时器提供CK_CNT时钟。 预分频器功能如下:

1. 预分频器是基于由一个3位寄存器(在TIMX_PSCR寄存器中)来控制的一个7位的计数器。由于该控制寄存器是带缓冲的所以它可以在系统运行中被改变。可以分频计速器的时钟频率为1到128之间的2的任意次幂。预分频器的值是通过一个预装载寄存器来载入的。一旦LS字节被写入时,保存当前要被使用值影子寄存器的值就被立即载入。对TIMX_PSCR寄存器的读操作是访问预装载寄存器,因此在读的过程中没有什么特别要注意的地方。 中断使能寄存器:TIMx_IER 位7:保留,须保持清零

位6:TIE:触发中断使能:0:触发中断禁止;1:触发中断使能; 位5:1 保留,须保持清零

位0:UIE:更新中断使能:0:更新中断禁止;1:更新中断使能 状态寄存器1(TIMX_SR1) 位7:保留,须保持清零

位6:TIF:触发中断标志位(此位在触发事件发生时(检测到TRGI信号的有效沿,在选择门控模

式时硬件置位。可以由软件清零。

)0:无触发事件产生;1:触发事件发生,此位当寄存器更新时由硬件置位(在timer4中该位保留) 位5:1 保留,须保持清零 位0:UIF:更新中断标志(此位在更新事件发生时由硬件置位。可以由软件清零) 0:无更新事件产生;1:跟新事件发生。 此位当寄存器更新时由硬件置位。

1. 如果TIM4_CR1中的UDIS=0,则发生在计数器溢出时。 2. 如果TIM4_CR1中的UDIS=0和URS=0,则发生在通过设置TIM4_EGR的UG位产生软件重新初始化计数时。 时间产生寄存器(TIM4_EGR) 位7:保留,须保持清零

位0:TG:触发事件产生:可用软件对该位置位以产生一个触发事件。该位由硬件自动清零。0:无触发发生;1:TIM4_SR1中TIF标志被置1.如果TIE位为1则产生中断。(注意:在TIM4中该位保留) 位5:1保留,须保持清零

位0:UG更新事件产生 0:无更新事件产生;1:计数器重新初始化并产生寄存器更新。(注意:分频计数器也同时清零) 计数器(TIMX_CNTR)

位7:0 计数器值

预分频寄存器(TIMX_PSCR) 位7:3 保留,须保持清零

位2:0 PSC 分频器值 分频器的值除分频时钟CLK_PSC 计数器时钟频率:

PSC中包含了每次更新事件(包含当通过TIM4_EGR寄存器的UG产生的更新事件)需要加载到实际分频寄存器的值。这就意味着为了使新的分频器值启用,必须产生一个更新事件。

自动重装载寄存器(TIMX_ARR)

位7:0 自动重装载的值

一、16位通用定时器(TIM2,TIM3,TIM5)

1.通用定时器TIM2有3个通道,TIM3有2个通道,TIM5与TIM2类似但是带有两个额外的寄存器,用于定时器的同步和级联。

通用寄存器由带有可编程预分频器的16位自动装载计数器构成。

2.适合的场合:

基本的定时;测量输入信号的脉冲长度(输入捕获);产生输出波形(输出比较,PWM和单脉冲);与其他定时器或者外部信号同步(外部时钟,复位,触发和使能信号)(仅针对带有TIM5的芯片) 定时器可由内部时钟驱动。 3.TIM2和TIM3的主要功能: 16位向上计数和自动装载计数器;

4位可编程预分频器,计数器时钟频率的分频系数为1~32768之间2的幂

3个独立通道:输入捕获,输出比较,PWM生成(边缘对齐模式),单脉冲模式输出 如下事件发生时产生中断:

更新:计数器向上溢出,计数器初始化(通过软件); 输入捕获; 输出比较;

4.TIM5的主要功能:

16位向上计数和自动装载计数器;

4位可编程预分频器,计数器时钟频率的分频系数值为1~32768之间2的幂; 3个独立通道: 输入捕获; 输出比较;

PWM生成(边缘对齐模式); 但脉冲模式输出; 如下事件发生时产生中断:

更新:计数器向上溢出,计数器初始化(通过软件) 输入捕获; 输出比较;

5.时基单元包含:16位向上计数器;预分频器;16位自动装载寄存器 没有重复寄存器。

计数器使用内部时钟Fmaster,它由CK_PSC提供,并经过预分频器分频产生计数器时钟CK_CNT。 预分频器的实现:

预分频器基于4位寄存器的16位计数器,由于寄存器带有缓冲器所有可以随时修改预分频的数值。计数器可以取值为1到32768质检单饿2的幂进行分频。

计数器时钟频率的计算公式: fCK_CNT = fCK_PSC/2(PSCR[3:0])]

预分频器的值由预装载寄存器写入。一旦写入预装载寄存器的LS字节时,带有当前使用值的影子寄存器就被写入了新的值。

新的预分频值在下一个周期时生效(在下一个更新事件之后)。

对TIMX_PSCR寄存器的读操作通过预装载寄存器实现,因此可以随时读取而不受限制。

5.计数器的操作

时钟/触发控制器(这个以及相应的TIMX_CR2和TIMX_SMCR寄存器仅仅存在于TIM5中)

捕获/比较通道:

输入部分:定时器有两个输入通道,通道1在内部链接到比较器。 6.中断:

通用定时器包括4个中断源:

捕获/比较3中断;捕获/比较2中断;捕获/比较1中断;更新中断

使用中断功能时,需要先设置TIMX_IER寄存器的CC3IE位或CC2IE或者CC1IE位使能中断请求。

通过软件设置TIMX_EGR寄存器的相应位也能产生不同的中断源。 7.TIM2,3,5寄存器

控制寄存器1(TIMX_CR1)

位7 ARPE 自动重装载允许位 0:TIMX_ARR寄存器没有预装载寄存器可以缓冲;可以直接对其进行写操作;1:TIMX_ARR寄存器通过预装载寄存器可以缓冲。 位3 OPM 单脉冲模式 0:在发生更新事件时,计数器不停止;1:当发生下一次更新事件时(清除CNE),计数器停止; 位2 URS 更新请求源 0:当更新请求源使能时,只要寄存器被更新了就产生更新中断;1 当更新请求使能时,只有计数器溢出才产生更新中断。 位1 UDIS 禁止更新 软件通过该位允许或者禁止UEV事件的产生

0:只要计数器溢出,或者产生了软件更新,或者通过时钟/触发模式控制器产生了硬件复位,就产生更新事件。

1:不产生更新事件,影子寄存器(ARR,PSC,CRRX)保持它们的值,如果设置了UG则计数器和预分频器被重新初始化。 位0 CEN 使能计数器 0:禁止计数器 1:使能计数器 8.控制寄存器2(TIM5_CR2) 该寄存器只有TIM5中才有。

触发从模式控制寄存器(TIM5_SMCR) 中断使能寄存器(TIMX_IER)

位7 TIE 触发中断使能 0:触发中断禁用 1:触发中断使能 位5:4 保留

位3 CC3IE 允许捕获/比较3中断 0:禁止捕获/比较3中断;1:允许捕获/比较3中断

位2 CC2IE 允许捕获/比较2中断 0:禁止捕获/比较2中断;1:允许捕获/比较2中断

位1 CC1IE 允许捕获/比较1中断 0:禁止捕获/比较1中断;1:允许捕获/比较1中断

位0 UIE 允许更新中断 0:禁止更新中断;1:允许更新中断; 状态寄存器1(TIMX_SR1) 位7 保留 位6 TIF 触发中断标志 当发生触发事件时该位由硬件设置置1(在TRGI信号上检测到有效的触发沿,当选择门控模式时,上升及下降沿都有效)。它由软件清0.

0:没有触发事件发生;1:触发中断悬挂 注意在TIM2和TIM3中该位保留。 位5:4 保留

位3 CC3IF 捕获/比较3中断标志 位2 CC2IF 捕获/比较2中断标志 位1 CC1IF 捕获/比较1中断标志 如果通道CC1配置位输出模式,当计数器值与比较值匹配时该位由硬件置1,由软件清零。

0:无匹配发生;

1:TIMX_CNT的值与TIMX_CCR1的值匹配

如果通道CC1配置位输入模式,它由软件清零或通过读TIMX_CCR1L清零 0:无输入捕获产生; 1:计数器值已被捕获(拷贝)到TIMX_CCR1(在IC1上检测到所选极性相同的边沿)。 位0 UIF 更新中断标志

当产生更新事件该位由硬件置1,软件清零。 0:无更新事件发生;

1:更新事件等待响应。当寄存器更新时该位由硬件置1; ——若TIMX_CR1寄存器的UDIS=0.计数器溢出;

——若TIMX_CR1寄存器的UDIS=0,URS=0,当TIMX_EGR寄存器的UG=1时产生更新事件(软件对计数器CNT重新初始化) 状态寄存器2(TIMX_SR2) 位7:4 保留

位3 CC3OF 捕获/比较3过捕获标志 位2 CC2OF 捕获/比较2过捕获标志 位1 CC1OF 捕获/比较1过捕获标志

只有当对应通道设置为输入捕获模式下,才会被硬件置位;软件写0清除该位。

0:没有检测到过捕获;

1:CC1IF标志已经置位的情况下,计数器的值又被捕获到TIMX_CCR1寄存器中。 位0 保留 硬件强制为0

事件发生寄存器(TIMX_EGR) 位7 保留 位6 TG 产生触发事件 该位由软件置1,用于产生一个触发事件,由硬件自动清0 0:无动作;

1:TIMX_SR1的TIF标志被置1.如果TIE为1则产生一个中断。注意在TIM2和TIM3中,该位保留 位5:4 保留

位3 CC3G 产生捕获/比较3事件 位2 CC2G 产生捕获/比较2事件 位1 CC1G 产生捕获/比较1事件 该位由软件置1,用于产生一个捕获/比较事件,由硬件自动清零。

0:无动作;

1:在通道CC1上产生一个捕获/比较事件 若通道CC1设置位输出:

设置CC1IF=1,若开启对应的中断,则产生相应的中断。 若通道CC1配置位输入:

当前的计数器值捕获至TIMX_CCR1寄存器,设置CC1IF=1,若开启对应的中断,则产生相应的中断。若CC1IF已经为1,则设置CC1OF=1. 位0 UG 产生更新事件 该位由软件置1,由硬件自动清零 0:无动作;

1:重新初始化计数器,并产生一个更新事件。注意预分频器的计数器也被清零。

计数器高位(TIMX_CNTRH) 位7:0 CNT 计数器的值(MSB) 计数器低位(TIMX_CNTRL) 位7:0 CNT 计数器的值(LSB)

#define ulong unsigned long unsigned int temp; void delay(ulong i) {

ulong j;

for(j=0;j

void CLK_Configuration(void); void GPIO_Configuration(void); void TIM2_Configuration(void); void EXIT_Configuration(void); void main(void) {

CLK_Configuration(); GPIO_Configuration(); EXIT_Configuration(); TIM2_Configuration(); enableInterrupts(); while (1) { } }

void CLK_Configuration(void) {

/* Fmaster = 16MHz */

CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); }

void GPIO_Configuration(void) {

/* GPIOD reset */ GPIO_DeInit(GPIOB); GPIO_DeInit(GPIOD);

/* Configure PD1 (LED1) as output push-pull low (led switched on)10MHZ */

GPIO_Init(GPIOD, GPIO_PIN_2, GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(GPIOB, GPIO_PIN_1, GPIO_MODE_IN_FL_IT); }

void TIM2_Configuration(void)

{

TIM2_DeInit();///设置timer2定时器 TIM2_TimeBaseInit( TIM2_PRESCALER_2048 ,8000); /*对TIM2时钟进行预分频得到计数时钟 */

TIM2_ITConfig(TIM2_IT_UPDATE ,ENABLE); /*允许更新中断使能*/

//TIM2_GenerateEvent(TIM2_EVENTSOURCE_UPDATE); /*设置事件源为更新事件*/

// TIM2_UpdateRequestConfig(TIM2_UPDATESOURCE_REGULAR );/*更新请求使能,只有当计数器溢出时产生更新中断*/

// TIM2_SelectOnePulseMode( TIM2_OPMODE_REPETITIVE ); /*发生更新事件时计数器不停止*/

TIM2_SetCounter(65536-8000); /*16位向上计数器初值*/

TIM2_Cmd(ENABLE); /*使能计数器*/ }

void EXIT_Configuration(void) {

EXTI_DeInit();

EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOB, EXTI_SENSITIVITY_FALL_ONLY); }

/*TIM2定时/向上溢出中断编号为13,中断编号+2*/ #pragma vector=15

__interrupt void TIM2_UPD_OVF_BRK_IRQHandler (void) {

GPIO_WriteReverse(GPIOD, GPIO_PIN_2); TIM2_ClearITPendingBit(TIM2_IT_UPDATE); }

//////////通用寄存器TIM2,3,5既然这样应该没有太大的区别 #pragma vector=6

__interrupt void EXIT_PORTB_IRQHander(void) {

if((GPIO_ReadInputData(GPIOB)&GPIO_PIN_1)==0x00) {

temp++;

switch(temp) {

case 1:TIM2_TimeBaseInit( TIM2_PRESCALER_256 ,8000);break;

case 2:TIM2_TimeBaseInit( TIM2_PRESCALER_512 ,8000);break; case 3:TIM2_TimeBaseInit( TIM2_PRESCALER_1024 ,8000);break; case 4:TIM2_TimeBaseInit( TIM2_PRESCALER_2048 ,8000);break; case 5:TIM2_TimeBaseInit( TIM2_PRESCALER_4096 ,8000);break; case 6:TIM2_TimeBaseInit( TIM2_PRESCALER_8192 ,8000);break; default:TIM2_TimeBaseInit( TIM2_PRESCALER_2048 ,8000),temp=1; } } }

此例子中,即使不适用更新事件也是可以使用的,就是单纯的作为定时器使用。但是什么时候用更新事件呢?更新事件包括溢出中断和初始化中断等,这个到底怎么回事?

TIME1与TIM2,3,5与TIM4,6不同:

STM8S提供三种类型的TIM定时器:高级控制型(TIM1),通用型(TIM2,TIM3,TIM5)和基本型定时器(TIM4和TIM6)。 TIM1,2,3,5都是16位,TIM4,6是8位。

TIM1(高级控制定时器)由一个16位的自动装载计数器组成,它由一个可编程的预分频器驱动。包括四个不同的捕获/比较通道。 高级控制定时器用途: 1. 基本的定时;

2. 测量输入信号的脉冲宽度;

3. 产生输出波形(输出比较,PWM和单脉冲模式);

4. 对应不同事件(捕获,比较,溢出,刹车,触发)的中断;

5. 与TIM5/TIM6或者外部信号(外部时钟,复位信号,触发和使能信号)同步; 高级控制定时器广泛的适用于各种控制应用中,包括哪些需要中间对齐模式PWM的应用,该模式支持互补输出和死区时间控制。

高级控制定时器的时钟源可以是内部时钟也可以使外部时钟的信号,可以通过配置寄存器选择。 主要特性:

1.16位向上/向下,向上,向下自动装载计数器;

2.允许在指定数目的计数器周期之后更新定时器寄存器的重复计数器; 3.16位可编程(可以实现修改)预分频器,计数器时钟频率的分频系数位1~65536

之间任意数值;

4.同步电路,用于使用外部信号控制定时器以及定时器互联(某些型号的芯片没有此功能);

5.多达4个独立通道可以配置成: 输入捕获; 输出比较;

PWM生成(边缘或者中间对齐模式); 六步PWM输出; 单脉冲模式输出;

三个支持带互补输出,并且死区时间可编程的通道;

刹车输入信号可以将定时器输出信号置于复位状态或者一个已知状态。 产生中断的事件包括: 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者外部/内部触发) 触发事件(计数器启动,停止,初始化或者由外部/内部触发计数) 输入捕获; 输出比较; 刹车信号输入;

时基单元:16位向上/向下计数器;16位自动重载寄存器;重复计数器;预分频器 16位计数器,预分频器,自动重载寄存器和重复计数器寄存器都可以通过软件进行读写操作。 自动重载寄存器由预装载寄存器和影子寄存器组成。 什么是影子寄存器?

自动预装载已使能(TIM1_CR1寄存器的ARPE位置位)。在此模式下,写入自动重载寄存器的数据将被保存在预装载寄存器中,并在下一个更新事件(UEV)时传送到影子寄存器。 自动预装载已禁止(TIM1_CR1寄存器的ARPE位清除)。在此模式下,写入自动重载寄存器的数据将立即写入影子寄存器。

更新事件的产生:

1. 计数器向上或向下溢出;

2. 软件置位了TIM1_EGR寄存器的UG(更新事件发生)位; 3. 时钟/触发控制器产生了触发事件;

置位TIM1_CR1寄存器的UDIS位将禁止更新事件(UEV)。

计数器由预分频器的输出CK_CNT驱动,而CK_CNT仅在IM1_CR1寄存器的计数器使能位(CEN)被置位时才有效。 (在使能了CEN位的一个时钟周期后,计数器才开始计数)(好好看一下时钟各种周期之间关系)

写计数器的操作没有缓存,并且可以在任何时候写TIM1_CNTRH和TIM1_CNTRL寄存器,因此我们建议不要在计数器运行时写入新的数值,以免写入了错误的数值。

注意:不要使用LDW指令来读取16位计数器的值,因为此指令先读低位(LS)字

节,这样读出的数值是错误的

预分频器的实现:TIM1的预分频器基于一个由16位寄存器(TIM1_PSCR控制的16位计数器。由于这个控制器带有缓冲器,因此它能够在运行时被改变。预分频器可以将计数器的时钟频率按照1~65536之间任意值分频。 fCK_CNT = fCK_PSC / (PSCR[15:0] + 1)

预分频器的值由与装载寄存器写入,保存了当前使用值的影子寄存器在低位

(LS)写入时被载入。需两次单独的写操作来写16位寄存器,高位(MS)先写。

例题:应用8位定时器TIM4定时控制灯的闪动, #include \

#define uchar unsigned char #define uint unsigned int #define ulong unsigned long unsigned int temp;

void CLK_Configuration(void); void GPIO_Configuration(void); void TIM4_Configuration(void); void display(); void main(void) {

CLK_Configuration(); GPIO_Configuration(); TIM4_Configuration(); enableInterrupts(); while (1) { } }

void CLK_Configuration(void)

{

/* Fmaster = 16MHz */

CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV8); }

void GPIO_Configuration(void) {

/* GPIOD reset */ GPIO_DeInit(GPIOD);

GPIO_Init(GPIOD, GPIO_PIN_2, GPIO_MODE_OUT_PP_LOW_FAST); }

/////////////更新包括向上/向下计数溢出等,那么就要设置事件产生类型和更新中断使能,同时事件更新时计数器不能停止,使能计数器 void TIM4_Configuration(void) {

TIM4_DeInit();////////////定义定时器4;

TIM4_TimeBaseInit(TIM4_PRESCALER_128, 255);/////////定时器分频值设置 TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);/////////运行更新中断 TIM4_UpdateRequestConfig(TIM4_UPDATESOURCE_REGULAR);

TIM4_GenerateEvent( TIM4_EVENTSOURCE_UPDATE);///////////设置更新模式 TIM4_SelectOnePulseMode(TIM4_OPMODE_REPETITIVE); TIM4_SetCounter(255);////设置计数器值 TIM4_SetAutoreload(255); TIM4_Cmd(ENABLE); }

#pragma vector=25

__interrupt void TIM4_UPD_BRK_IRQHandler(void) {

temp++;

if(temp==100) {

GPIO_WriteReverse(GPIOD, GPIO_PIN_2); temp=0; }

TIM4_ClearFlag(TIM4_FLAG_UPDATE); }

////////////一次定时器中断频率=2MHZ/128/255/2=30.63,那么等闪烁的频率为大概是亮灭3秒!

窗口看门狗:

窗口看门狗用于监测由于外部干扰或不可预知的逻辑关系产生的软件错误,这样的软件错误通常会导致应用程序不会按照预期的方式运行。除非程序在递减计数器的T6位变为0之前刷新递减计数器,看门狗电路将在一个预设的时间间隔后产生系统复位;如果在7位的递减计数器数值达到窗口寄存器数值之前刷新递减计数器,同样会产生系统复位。这就意味着智能在一个有限的时间窗口内刷新递减计速器。

WWDG主要功能:

1. 可编程的自由运行递减计数器; 2. 有条件的复位:

——如果开启了看门狗,当递减计数器的数值小于0x04时产生复位

——如果开启了看门狗,当在指定的时间窗口之外重加载递减计数器的数值时产生复位;

3. 硬件或软件启动看门狗(由选择字节指定) 4. 可在HALT指令时产生复位(由选择字节配置)

模拟/数字转换器:ADC

1. ADC1和ADC2是10位的逐次比较型模拟数字转换器。提供多达16个多功能的通道(实际准确的通道数量在数据手册的引脚说明)。A/D转换得各个通道可以执行单次和连续的转换模式。

2. 相对于ADC2,ADC1具有一些扩展功能,包括扫描模式,带缓存的连续模式以及模拟看门狗。

3. ADC1和ADC2的功能如下: 10位的分辨率;

单次和连续的转换模式;

可编程的(转换频率的)预分频:Fmaster可以被分频2到18;

可以选择ADC专用外部中断(ADC_ETR)或者定时器触发信号(IRGO)来作为外部触发信号;

模拟放大(对于具有Vref引脚的型号); 转换结束时可产生中断; 灵活的数据对齐方式;

ADC输入电压范围:VSSA ≤ VIN ≤ VDDA 4. 扩展功能

ADC1具有以下扩展功能: 带缓冲的连续转换模式; 单次和连续转换的扫描模式;

具有上限和下限门槛的模拟看门狗; 模拟看门狗事件发生可产生中断;

5. 引脚描述: Vdda 输入,模拟电源 模拟电源供电端。对于没有外部Vdda引脚的产品该输入引脚是连接到Vdd端的。

VSSA 输入,模拟电源地 模拟电源地端。对于没有外部VSSA引脚的产品该输入引脚是连接到VSSA端的。 Vref- 输入,模拟参考负极 Vref+ 输入,模拟参考正极

AIN[15:0] 模拟输入信号 多达16个模拟输入通道,每次只一个通道ADC转换。

ADC_ETR 数字输入通道 外部触发信号

ADC时钟是由Fmaster时钟经过预分频后供给的。时钟的预分频因子是由ADC_CR1寄存器的SPSEL[2:0]决定的。 通道的选择:

有多达16个外部输入通道。实际上外部通道的数量取决于MCU封装大小。 如果在一次转换过程中改变通道选择,那么当前的转换被复位同时一个新的开始指令脉冲被发送到ADC。

转换模式:单次模式,连续模式,带缓存的连续模式,单次扫描模式和连续扫描模式。

1. 在单次转换模式中,ADC仅在由ADC_CSR寄存器的CH[3:0]选定的通道上完成一次转

换。该模式是在当CONT位为0时通过置位ADC_CR1寄存器的ADON位来启动的。 一旦转换完成,转换后的数据存储在ADC_DR寄存器中,EOC(转换结束)标志被置EOCIE 被置位将产生一个中断。

程序完成任务:流水灯显示,按键控制不同速率,即按键控制流水灯以不同的速率显示。 #include \

#define uchar unsigned char #define uint unsigned int #define ulong unsigned long unsigned int temp; void delay(ulong i) { ulong j; for(j=0;j

void CLK_Configuration(void); void GPIO_Configuration(void);

void TIM2_Configuration(void); void EXIT_Configuration(void); void main(void) {

CLK_Configuration(); GPIO_Configuration(); TIM2_Configuration(); EXIT_Configuration();

enableInterrupts(); while (1) { } }

void CLK_Configuration(void) {

/* Fmaster = 16MHz */

CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); }

void GPIO_Configuration(void) {

/* GPIOD reset */ GPIO_DeInit(GPIOB); GPIO_DeInit(GPIOD);

/* Configure PD1 (LED1) as output push-pull low (led switched on)10MHZ */ GPIO_Init(GPIOD, GPIO_PIN_0, GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(GPIOD, GPIO_PIN_1, GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(GPIOD, GPIO_PIN_2, GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(GPIOD, GPIO_PIN_3, GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(GPIOB, GPIO_PIN_1, GPIO_MODE_IN_FL_IT); }

void TIM2_Configuration(void) {

TIM2_DeInit();///设置timer2定时器

TIM2_TimeBaseInit( TIM2_PRESCALER_1024 ,8000); /*对TIM2时钟进行预分频得到计数时钟 */

TIM2_ITConfig(TIM2_IT_UPDATE ,ENABLE); /*允许更新中断使能*/ // TIM2_GenerateEvent(TIM2_EVENTSOURCE_UPDATE); /*设置事件源为更新事件*/

// TIM2_UpdateRequestConfig(TIM2_UPDATESOURCE_REGULAR );/*更新请求使能,只有当计数器溢出时产生更新中断*/

// TIM2_SelectOnePulseMode( TIM2_OPMODE_REPETITIVE ); /*发生更新事件时计数器不停止*/

TIM2_SetCounter(65536-8000); /*16位向上计数器初值*/ TIM2_Cmd(ENABLE); /*使能计数器*/ }

void EXIT_Configuration(void) {

EXTI_DeInit();

EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOB, EXTI_SENSITIVITY_FALL_ONLY); }

/*TIM2定时/向上溢出中断编号为13,中断编号+2*/ #pragma vector=15

__interrupt void TIM2_UPD_OVF_BRK_IRQHandler (void) {

GPIO_WriteHigh(GPIOD, GPIO_PIN_0); GPIO_WriteHigh(GPIOD, GPIO_PIN_1); GPIO_WriteHigh(GPIOD, GPIO_PIN_2); GPIO_WriteHigh(GPIOD, GPIO_PIN_3); switch(temp) {

case 1: GPIO_WriteReverse(GPIOD, GPIO_PIN_1);break; case 2: GPIO_WriteReverse(GPIOD, GPIO_PIN_2);break; case 3: GPIO_WriteReverse(GPIOD, GPIO_PIN_3);break; default:GPIO_WriteReverse(GPIOD, GPIO_PIN_0),temp=0; }

TIM2_ClearITPendingBit(TIM2_IT_UPDATE); }

//////////通用寄存器TIM2,3,5既然这样应该没有太大的区别 #pragma vector=6

__interrupt void EXIT_PORTB_IRQHander(void) {

if((GPIO_ReadInputData(GPIOB)&GPIO_PIN_1)==0x00) { temp++; if(temp==5) temp=0; } }

GPIO输出和输入

今天要进行的实验,是利用GPIO进行输入和输出。在ST的三合一开发板上,按键接在GPIO的PD7上,LED接在GPIO的PD3上,因此我们要将GPIO的PD7初始化成输入,PD3初始化成输出。

关于GPIO的引脚设置,主要是要初始化方向寄存器DDR,控制寄存器1(CR1)和控制寄存器2(CR2),寄存器的每一位对应GPIO的每一个引脚。具体的设置功能定义如下: DDR CR1 CR2 引脚设置 0 0 0 悬浮输入 0 0 1 上拉输入 0 1 0 中断悬浮输入 0 1 1 中断上拉输入 1 0 0 开漏输出 1 1 0 推挽输出

1 X 1 输出(最快速度为10MHZ)

另外,输出引脚对应的寄存器为ODR,输入引脚对应的寄存器为IDR。

下面的程序是检测按键的状态,当按键按下时,点亮LED,当按键抬起时,熄灭LED。 同样也是利用ST的开发工具,先生成一个C语言程序的框架,然后修改其中的main.c,修改后的代码如下。

编译通过后,下载到开发板,运行程序,按下按键,LED就点亮,抬起按键,LED就熄灭了。

另外,要注意,将STM8S207C_S.h拷贝到当前项目的目录下。

// 程序描述:检测开发板上的按键,若按下,则点亮LED,若抬起,则熄灭LED // 按键接在MCU的GPIO的PD7上 // LED接在MCU的GPIO的PD3上

#include \ main() {

PD_DDR = 0x08;

PD_CR1 = 0x08; // 将PD3设置成推挽输出 PD_CR2 = 0x00;

while(1) // 进入无限循环 {

if((PD_IDR & 0x80) == 0x80) // 读入PD7的引脚信号

{

PD_ODR = PD_ODR & 0xF7; // 如果PD7为1,则将PD3的输出设置成0,熄灭LED } else {

PD_ODR = PD_ODR | 0x08; // 否则,将PD3的输出设置成1,点亮LED }

} }

STM8的C语言编程(3) ―― GPIO输出

与前些日子写的用汇编语言进行的实验一样,从今天开始,要在ST的三合一开发板上,用C语言编写程序,进行一系列的实验。

首先当然从最简单的LED指示灯闪烁的实验开始。

开发板上的LED1接在STM8的PD3上,因此要将PD3设置成输出模式,为了提高高电平时的输出电流,要将其设置成推挽输出方式。这主要通过设置对应的DDR/CR1/CR2寄存器实现。

利用ST的开发工具,先生成一个C语言程序的框架,然后修改其中的main.c,修改后的代码如下。

编译通过后,下载到开发板,运行程序,可以看到LED1在闪烁,且闪烁的频率为5HZ。

/* MAIN.C file *

* Copyright (c) 2002-2005 STMicroelectronics */

#include \

// 函数功能:延时函数

// 输入参数:ms -- 要延时的毫秒数,这里假设CPU的主频为2MHZ // 输出参数:无 // 返 回 值:无 // 备 注:无

void DelayMS(unsigned int ms) {

unsigned char i; while(ms != 0) {

for(i=0;i<250;i++) { }

for(i=0;i<75;i++) { } ms--; } }

// 函数功能:主函数

// 初始化GPIO端口PD3,驱动PD3为高电平和低电平 // 输入参数:ms -- 要延时的毫秒数,这里假设CPU的主频为2MHZ // 输出参数:无 // 返 回 值:无 // 备 注:无 main() {

PD_DDR = 0x08;

PD_CR1 = 0x08; // 将PD3设置成推挽输出 PD_CR2 = 0x00; while(1) {

PD_ODR = PD_ODR | 0x08; // 将PD3的输出设置成1 DelayMS(100); // 延时100MS

PD_ODR = PD_ODR & 0xF7; // 将PD3的输出设置成0 DelayMS(100); // 延时100MS } }

需要注意的是,当生成完框架后,为了能方便使用STM8的寄存器名字,必须包括STM8S207C_S.h,最好将该文件拷贝到C:\\Program Files\\STMicroelectronics\\st_toolset\\include目录下,拷贝到工程目录下。或者将该路径填写到该工程的Settings…中的C Compiler选项Preprocessor的Additional include中,这样编译时才会找到该文件。

本文来源:https://www.bwwdw.com/article/mhtr.html

Top