历史上的今天
返回首页

历史上的今天

今天是:2024年11月04日(星期一)

正在发生

2021年11月04日 | 一起学mini2440裸机开发(五)--定时器0的基础实验

2021-11-04 来源:eefocus

实验前的准备 


既然是关于定时器的实验,肯定要用到系统时钟,所以一定要保证系统时钟设置好,在这里需要的PCLK为50MHz。第二节分析MDK自带的S3C2440.c可以知道,默认的是不初始化系统时钟(是否选择初始化可以通过修改S3C2440.s中的CLOCK_SETUP来选择)。那么在这里首先修改一下S3C2440.s,对时钟进行初始化。


在这里只需要设置一处即可将 CLOCK_SETUP     EQU     0修改为CLOCK_SETUP     EQU     1,这样系统在启动时就会对咱们的芯片进行初始化,初始化之后的系统时钟值为:FCLK=300MHz,HCLK=100MHz,PCLK=50MHz。


实验1


实验实现的功能:使用定时器0的定时功能,是LED每秒钟闪烁一次。   


因为在启动代码阶段,已经对系统时钟进行初始化,PCLK=50MHz,定时器的输入频率由PCLK分频得到,如图1所示展示了从晶振输入频率到定时器工作频率产生的整体过程。

下图是我的定时器工程的文件布局图:

从上图可以看出,这个工程需要咱们自己编写的文件一共有5个:main.c  timer.c   timer.h    led.c   led.h


实验代码:


main.c文件内容:


/*

*  使用定时器0的定时功能,使LED灯每秒钟闪烁一次

*/


#include

#include"timer.h"

#include"led.h"


int main()

{   

     int flag=0;

     Led_Init();   //对LED初始化为全灭

    Timer0_Init();  //定时器0初始化,打开定时器0,定时器0开始进行减1计数。

     while(1)

    {

        if(SRCPND&(1<<10))     //当TCNT0中的计数值减为0时,定时器0中断标志会置位

        {                                     //因此,在程序中可以通过不断的检测该位是否置位来判断1s定时

             flag=!flag;                     //是否到达。定时器0中断标志位位于SRCPND寄存器的第10位

             SRCPND|=(1<<10);     //清除定时器0中断标志位

         }

         if(1==flag)                      //判断falg是否为1,这里使用一个小技巧,使用if(1==flag)。也可以


                                              //使用if(flag==1)。

        {

            Led1_On();

        }  

        else

       {

           Led1_Off();

        }

       }

}


    timer.c文件内容


            #include   //s3c2440.h对S3C2440芯片的一些地址的宏定义

            #include"timer.h"


 /***************************************************************

* 函数名称:void Timer0_Init(void)

* 参数说明:无

* 全局变量:无

* 返 回 值:无

* 功    能:对于50MHz的PCLK,经过分频获得62.5KHz的定时器0

*     的输入时钟。

***************************************************************/

void Timer0_Init(void)

{

 TCFG0&=~(0xff);          //设置第1级分频系数,分频系数为99

 TCFG0|=99;


 TCFG1&=~(0xf);            //设置第2级分频系数,分频系数为8

 TCFG1|=0x02;               //62.5KHz=50MHz/(99+1)/8


 TCNTB0=62500;            //1s中断一次。经过上述分频器得到定时器0的输入时钟频率为62.5kHz,即定时

                                       //器每秒钟计数62500次。因此,初始化时,定时器0计数值初始值为62500,在这

                                       //里我们可以看出TCMPBn没有设置,因为咱们用它的默认值0,所以就不需要设置


 TCON|=(1<<1);             //开启手动更新位,即当定时器开启后,TCMPB0和TCNTB0中的值会加载到寄存


                                      //器TCMP0和TCNT0中

 TCON=0x09;                //关闭手动更新位,设置自动加载位,同时开启定时器,这样,TCNT0进行减1计


                                     //数,当TCNT0中的计数值减到0时,TCNTB0、TCMPB0中的数据分别会

                                     //自动加载到TCNT0、TCMP0中并进行新一轮的减1计数

}


timer.h文件内容:


#ifndef __TIMER_H__

#define __TIMER_H__


/***************************************************************

* 函数名称:void Timer0_Init(void)

* 参数说明:无

* 全局变量:无

* 返 回 值:无

* 功    能:对于50MHz的PCLK,经过分频获得62.5KHz的定时器0

*     的输入时钟。

***************************************************************/

void Timer0_Init(void);


#endif


led.c文件内容:


/*

*  在我的mini2440开发板上,4个led灯对应的GPIO引脚如下

*   LED1----GPB5

*   LED2----GPB6

* LED3----GPB7

*   LED4----GPB8

*   当GPIO引脚输出低电平时,对应的led灯亮,输出高电平时,对应的led灯灭。

*/


#include 

#include"led.h"


/***************************************************************

* 函数名称:void Led_Init(void)

* 参数说明:无

* 全局变量:无

* 返 回 值:无

* 功    能:led初始化函数,使4个led初始化为灭

*     的输入时钟。

***************************************************************/

void Led_Init(void)

{

 GPBCON&=~((3<<10)|(3<<12)|(3<<14)|(3<<16));  //注意这里设置寄存器的方式,采用先与后或的方式

 GPBCON|=((1<<10)|(1<<12)|(1<<14)|(1<<16));    //设置GPB5、6、7、8为输出功能


 GPBUP&=~((1<<5)|(1<<6)|(1<<7)|(1<<8));      //上拉电阻使能。上拉电阻的作用是:当GPIO引脚处于


                                                                          //第三态(既不是输出高电平,也不是输出低电平,而是呈


                                                                         //高阻态,即相当于没接芯片)时,它的电平状态由上拉

                                                                           //电阻、下拉电阻确定


 GPBDAT|=((1<<5)|(1<<6)|(1<<7)|(1<<8));      //初始化这4个引脚输出高电平,即4个led灯全灭。

}


led.h文件内容:


#ifndef __LED_H__

#define __LED_H__


#define Led1_On() {GPBDAT&=(~(1<<5));}       //在程序调用函数时,调用函数需要保存函数的返回地址,

#define Led1_Off() {GPBDAT|=(1<<5);}           //然后从函数返回是需要将返回地址赋值给PC,这些都会

#define Led2_On() {GPBDAT&=(~(1<<6));}    //使程序执行速度变慢。为了改善这种情况,对于这种

#define Led2_Off() {GPBDAT|=(1<<6);}         //代码量很小的程序段,可以使用宏的形式实现。

#define Led3_On() {GPBDAT&=(~(1<<7));}

#define Led3_Off() {GPBDAT|=(1<<7);}

#define Led4_On() {GPBDAT&=(~(1<<8));}

#define Led4_Off() {GPBDAT|=(1<<8);}

/***************************************************************

* 函数名称:void Led_Init(void)

* 参数说明:无

* 全局变量:无

* 返 回 值:无

* 功    能:led初始化函数,使4个led初始化为灭

*     的输入时钟。

***************************************************************/

void Led_Init(void);


#endif


以上实验1的代码我已经上传到csdn,如有需要可自行下载:http://download.csdn.net/detail/mybelief321/5371577,mske编译成功后,就可以仿真看到结果了。


上述实验1的已经说完了,再强调一下,我没有再编写代码另外设置系统时钟,而是用MDK自带的S3C2440.s来初始化的,只需要修改一处地方,本文章开头所示。


还有一处需要说明一下,那就是关于main函数里的中断。虽然定时器0中断标志还没有讲,但是我们可以先了解以下三点:


①SRCPND寄存器中的每一位代表一种类型的中断标志,当该位置1时,说明相应的中断发生了。


②定时器0中断标志位于SRCPND寄存器的第10位,当定时器0中的计数值减到0时,会触发定时器0中断标志,即SRCPND寄存器第10位会置1.


③清除定时器0中断标志的方法是:想SRCPND寄存器的第10位写入1即可。


实验2


实验1主要是针对定时器的原理进行的实验,下面的实验是为了展示定时器0的脉冲宽度调制功能。


从下图可以看出,当TCMP0=TCNT0时,TOUT0引脚电平会发生翻转;当TCNT0中计数值减为0时,TOUT0引脚电平再次发生翻转。因此,可以利用TOUT0引脚电平的两次翻转进行脉冲宽度调制,即PWM。查询S3C2440数据手册可以得到,TOUT0引脚对应的是GPB0引脚。

在实验1的基础上,修改timer.c中定时器0初始化函数。修改后的定时器0初始化函数如下:    


void  Timer0_Init(void)

{

 GPBCON&=~(3<<0);

 GPBCON|=(1<<1);


 TCFG0&=~(0xff);    //设置第1级分频系数,分频系数为99

 TCFG0|=99;


 TCFG1&=~(0xf);      //设置第2级分频系数,分频系数为8

 TCFG1|=0x02;        //62.5KHz=50MHz/(99+1)/8

                                //此时定时器0的工作频率为62500Hz


 TCNTB0=62;                  //由于此时定时器0的工作频率为62500Hz,即每秒种可以计数62500次,而其初始值为62,所以产生的方波

                                       //的频率为62500/62=1008Hz。又因为TCMP0=TCNT0/2,所以产生的方波高电平持续时间和低电平持续时间

 TCMPB0=TCNTB0/2;   //各占一半。


 TCON|=(1<<1); //开启手动更新位,即当定时器开启后,TCMPB0和TCNTB0中的值会加载到寄存器TCMP0和TCNT0中

 TCON=0x0d;     //关闭手动更新位,设置自动加载位,同时开启定时器,设置当TCMP0=TCNT0时,TOUT0引脚电平发生翻转

}


程序总体流程:


①开启定时器0后,TCNTB0、TCMPB0中的值分别装入TCNT0和TCMP0中,然后,TCNT0从初值62开始减1计数;


②当TCNT0=TCMP0=31时,TOUT0引脚电平发生翻转;


③TCNT0继续减1计数,当TCNT0减为0时,TOUT0引脚电平再次发生翻转,此时恰好产生一个方波;


④TCNTB0、TCMPB0中的值被自动装入TCNT0、TCMP0中,TCNT0继续从初值62开始减1计数。


上述程序,占空比为50%,如果将 TCMPB0=TCNTB0/2 改为 TCMPB0=TCNTB0/4,那么输出方波的占空比发生了变化,变为75%,这就是所谓的PWM功能。


由于咱们的开发板的GPB0连接着蜂鸣器,所以你可以通过调节占空比来改变蜂鸣器的频率,将上述初始化函数修改后,直接make,仿真就可以了。

推荐阅读

史海拾趣

AMSCO [Austria micro systems AG]公司的发展小趣事

Austria Micro Systems AG(AMS)是一家总部位于奥地利的半导体制造商,专注于模拟IC、传感器和感应器解决方案。以下是 AMS 公司发展的五个相关故事:

  1. 创立与初期发展:AMS 公司成立于1981年,最初是一家小型的半导体公司,成立之初主要从事晶圆制造和生产模拟集成电路(IC)。在公司创始人的领导下,AMS 迅速崛起,凭借着其创新能力和对技术的独特洞察力,迅速在半导体市场上占据了一席之地。

  2. 技术创新与产品扩展:随着时间的推移,AMS 公司不断进行技术创新,并不断扩展其产品线。公司致力于开发高性能、低功耗的模拟IC和传感器解决方案,以满足汽车、工业、医疗等各个领域的客户需求。AMS 的产品涵盖了光学传感器、环境传感器、声学传感器等多个领域。

  3. 全球化发展与市场拓展:AMS 公司通过不断拓展全球市场,加强与客户和合作伙伴的合作关系,实现了快速的业务增长。公司在欧洲、亚洲和美洲设立了多个销售办事处和生产基地,建立了完善的全球供应链和销售网络。公司的产品销售网络覆盖了全球范围,得到了国内外客户的广泛认可。

  4. 收购与合并:为了进一步壮大自身实力和拓展市场份额,AMS 公司通过收购和合并等方式不断强化自身。公司先后收购了一些技术领先的公司,扩大了产品线和市场份额。此举进一步提升了公司在模拟IC和传感器领域的竞争优势,加速了公司的业务增长。

  5. 持续创新与未来展望:AMS 公司将继续致力于技术创新和产品研发,不断提升产品性能和品质水平。公司将关注新兴技术和市场趋势,积极布局未来的发展方向,包括人工智能、物联网、汽车电子等领域。同时,公司还将加强与客户和合作伙伴的合作,共同推动行业的发展和进步。

Ampire Co Ltd公司的发展小趣事

Ampire Co., Ltd. 是一家总部位于中国深圳的汽车电子产品制造商,专注于汽车安全、娱乐和舒适性电子产品的研发、生产和销售。以下是关于 Ampire 公司发展的五个相关故事:

  1. 成立与初创阶段:Ampire 公司成立于 2002 年,起初主要从事汽车电子产品的贸易业务。公司的创始人致力于在汽车行业提供高品质的电子产品,以提升驾驶体验和车辆安全性。在公司初期,他们主要进口和销售一些汽车音响和影音产品。

  2. 技术创新与产品升级:随着市场需求的不断变化和技术的进步,Ampire 公司开始注重技术创新和产品升级。公司加大了对汽车安全和行车辅助系统的研发投入,推出了一系列高品质的后视摄像头、倒车雷达、行车记录仪等产品,以提高车辆的安全性和驾驶便利性。

  3. 品牌建设与市场拓展:Ampire 公司通过不断提升产品质量和服务水平,逐渐树立起了良好的品牌形象,并在国内外市场上获得了良好的口碑和知名度。公司积极参加国内外汽车电子展会和行业活动,拓展了国际市场,产品出口至欧美、东南亚等多个国家和地区。

  4. 生产基地建设与产能提升:为满足不断增长的市场需求,Ampire 公司逐步扩大了生产基地,并引进了先进的生产设备和技术。公司建立了完善的生产制造体系,实现了规模化生产和产能提升,保障了产品质量和交货期。

  5. 持续发展与未来规划:Ampire 公司持续致力于技术创新和产品升级,不断推出符合市场需求的新品。未来,公司计划进一步加大在汽车安全、智能驾驶和车载娱乐等领域的研发投入,积极探索人工智能、互联网车联网等新技术的应用,为客户提供更加智能、安全和便捷的汽车电子产品。

这些故事展示了 Ampire 公司从创立初期到如今在技术创新、产品升级、品牌建设、生产基地建设以及未来规划等方面取得的重要进展。

得倍(DBIC)公司的发展小趣事

倍(DBIC)公司自创立之初,就致力于在电子行业中进行技术创新。公司投入大量资源进行研发,成功推出了一系列具有革命性的产品,如高效能芯片和智能传感器。这些产品不仅提高了生产效率,还满足了市场对智能化、高效能电子产品的需求。随着技术的不断进步,倍(DBIC)公司逐渐在行业中树立了技术领先的形象,吸引了众多合作伙伴和客户。

FILTRAN公司的发展小趣事

在激烈的市场竞争中,倍(DBIC)公司不断优化供应链管理,降低成本,提高效率。公司与全球多家供应商建立了长期稳定的合作关系,确保原材料的稳定供应。同时,倍(DBIC)公司还加强了对生产过程的监控和管理,确保产品质量和交货期。这些措施使倍(DBIC)公司在成本控制和交付能力方面具备了明显的竞争优势。

Gems Sensors & Controls公司的发展小趣事

Gems Sensors & Controls公司始终致力于技术创新和产品研发。数十年来,公司不断推出新型号的液位、流量和压力传感器、微型电磁阀及预装射流系统等产品,以满足客户日益多样化的需求。这些产品凭借其卓越的性能和稳定的质量,在行业内赢得了广泛的赞誉和认可,也推动了整个传感器行业的进步和发展。

Esico-Triton公司的发展小趣事

近年来,Esico-Triton越来越重视企业的可持续发展和社会责任。公司开始着手研发更加环保的电子产品,减少有害物质的使用,推动循环经济的发展。此外,Esico-Triton还积极参与社会公益活动,支持教育事业和环境保护项目,以实际行动回馈社会。这些举措不仅提升了公司的品牌形象,也为电子行业的可持续发展树立了典范。

问答坊 | AI 解惑

用好ThinkPad电源管理软件

ThinkPad笔记本一直备受企业和个人用户的青睐,除了其良好的稳定性、耐用性和舒适性之外,一些个性化的硬件设计及与之相配套的软件亦是其中一个重要因素。下面,就让我们通过ThinkPad电源管理软件来感受一下“黑砖头”中蕴藏的个性化风格,让你能够 ...…

查看全部问答>

分享一本书

8051单片机实践和应用,还不错的…

查看全部问答>

C语言中的求2幂次的函数

如题,C语言中有没有那样的函数,比如我给出16,2的4次方是16,4就是我想要的,有没有函数能帮我把4算出来的?…

查看全部问答>

把wince驱动学好到底有多难啊?

突然觉得自己掉进了一个无底洞,本来是想学应用程序,老板说驱动缺人,要我去学驱动,我对驱动一窍不通,但是想去尝试一下就答应了,学了一段时间的驱动我发现这一块什么都要懂,C、C++、还要看电路图懂硬件,晚上做梦都会梦到那些代码,在我看来想 ...…

查看全部问答>

微指令操作流程

问个微指令操作流程的 ADD  Rd,disp.指令为双子长指令。disp为位移量。指令的操作流程图如下: 1.pc->MAR,M->MDR,MDR->IR,PC+1; 2.pc->MAR,M->MDR,MDR->MAR,PC+1; 3.M->MDR,MDR->A, 4.Rd->B, 5.A+B->Rd; 我不理解第二和第三个,di ...…

查看全部问答>

做DSP视频口驱动,卡住看不下去了。

    准备学习DSP视频口(VP口)的驱动,先是看操作系统和驱动开发手册,了解驱动的工作原理和程序结构,然后看VP口的工作原理,接着发现不了解数据传输协议是不行的,于是开始看了下BT.656的传输协议,结果卡在这看不动了,对于协议中场的 ...…

查看全部问答>

为什么没结果?

dsp的c语言编程,为什么没结果?编译,链接都没错 #include \\"stdio.h\\" void main()      {      int a;    a=4;    printf(\\"%d\\",a);    } ...…

查看全部问答>

stm32 usart不能发数,使用查询方法

公司的板子是,485 通讯,使用stm32f103re,USART1通讯,485使用端口GPIOA PIN11,USART_RX对应GPIOA PIN10,USART_TX 对应GPIOA PIN9 不知为什么,我现在只是做了一个要放数据的程序,可是就是无法下发数据。可以保证连线等硬件没有任何问题。& ...…

查看全部问答>

有过空气电容没?

想买个1000pf的空气电容,真难买,谁有啊?…

查看全部问答>

MSP430F5438 TA0CCR0 寄存器

MSP430F5438  TA0CCR0  寄存器中的各位详细说明有么?还是就是一个16为的数据存储器…

查看全部问答>