tiny6410裸机实验第10章--------------PWM定时器(原理及代码)
2014-03-12 10:47
281 查看
【说明】
S3C6410带有5个32位定时器,其中定时器4是内部定时器,没有引出外部引脚的,这一节我们就来试试操作定时器中断。学了这个定时器操作之后,我们再利用它来写一个进程调度程序,实现最最简单的进程并发。
【原理】
S3C6410的5个定时器中,定时器0和1有PWM功能,其他没有
PWM具有两种操作,即自动装载模式和一次触发模式,
所提供的定时器有双缓冲功能,对定时器的操作不会影响定时器当前的运作
看看电路图
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/07/0f04ddf8b30d9a13ed4a7e61246f331b)
1)源时钟为PCLK,我们在时钟初始化的时候将其设置为了66MHZ
2)源时钟要进过两次分频才到达逻辑控制单元,所以显然我们得设置这2个分频咯
【寄存器操作】
定时器的寄存器比较少所以操作起来非常简单
1】定时器配置寄存器
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/07/ab330883bbde4dcec560060180803f8e)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/07/eb173b575a2eb6cd9e2035baed4b3161)
1)这个寄存器就是第一个分频器的设置,我们要用定时器0,所以就设置前面8位
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/07/42de9f590d03681dddba96fba62c1922)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/07/5d38e05baf0817b0a1d81cc9240acef0)
2)设置第二次分频。。我们设置为0100
2】设置定时时间
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/07/b7c461d58bff2460c95b527f5bf9f076)
1)往这个寄存器写入的就是定时的时间,当然,具体数值需要和最终的时钟频率有关。
2)其实定时器本身并不是利用这个寄存器计时的,而是用TCNTN0,但是那是一个内部寄存器,无法直接操作。
3)当TCNTN0到时的时候,若设置为自动装载模式,则TCNTB0的值会被复制到TCNTN0
3】设置比较时间
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/07/56f1b1a7da5fcd4a3404717810f984bc)
1)这个一般设置为0,就是说TCNTB0里面的数值减少到什么值的时候产生中断的。
4】控制寄存器
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/07/910fe98ef9d0f9d96b584d0bfa7cccec)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/07/34d3a248d0bfdcbbdca76568272807ef)
1)我们需要设置一下手动更新位,然后再清手动更新位。。。为什么呢?我也知道。。。
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/07/9e1ef36131ec4d1dabebdd91ee58f0ed)
2)启动计时器
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/07/c0ee587954f31cf5d0cc9cd122b73b68)
3)自动装载模式
5】使能中断
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/07/051979a37d196221fba016e56de69a4f)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/07/5f0722610a413fbfabf3099efda031eb)
1)这个使能定时器,使其能发送中断
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/07/f3d72df67315599d75be11082d8bc1a6)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/07/2612a1626143ca7f9b219a3348ccba6f)
2)在中断控制器中使能
【中断处理】
我们只是简单得在串口打印一句话。然后清中断。
【源代码】
S3C6410带有5个32位定时器,其中定时器4是内部定时器,没有引出外部引脚的,这一节我们就来试试操作定时器中断。学了这个定时器操作之后,我们再利用它来写一个进程调度程序,实现最最简单的进程并发。
【原理】
S3C6410的5个定时器中,定时器0和1有PWM功能,其他没有
PWM具有两种操作,即自动装载模式和一次触发模式,
所提供的定时器有双缓冲功能,对定时器的操作不会影响定时器当前的运作
看看电路图
1)源时钟为PCLK,我们在时钟初始化的时候将其设置为了66MHZ
2)源时钟要进过两次分频才到达逻辑控制单元,所以显然我们得设置这2个分频咯
【寄存器操作】
定时器的寄存器比较少所以操作起来非常简单
1】定时器配置寄存器
1)这个寄存器就是第一个分频器的设置,我们要用定时器0,所以就设置前面8位
2)设置第二次分频。。我们设置为0100
2】设置定时时间
1)往这个寄存器写入的就是定时的时间,当然,具体数值需要和最终的时钟频率有关。
2)其实定时器本身并不是利用这个寄存器计时的,而是用TCNTN0,但是那是一个内部寄存器,无法直接操作。
3)当TCNTN0到时的时候,若设置为自动装载模式,则TCNTB0的值会被复制到TCNTN0
3】设置比较时间
1)这个一般设置为0,就是说TCNTB0里面的数值减少到什么值的时候产生中断的。
4】控制寄存器
1)我们需要设置一下手动更新位,然后再清手动更新位。。。为什么呢?我也知道。。。
2)启动计时器
3)自动装载模式
5】使能中断
1)这个使能定时器,使其能发送中断
2)在中断控制器中使能
【中断处理】
我们只是简单得在串口打印一句话。然后清中断。
【源代码】
#include "stdio.h" #define EINT0CON0 (*((volatile unsigned long *)0x7F008900)) #define EINT0MASK (*((volatile unsigned long *)0x7F008920)) #define EINT0PEND (*((volatile unsigned long *)0x7F008924)) #define PRIORITY (*((volatile unsigned long *)0x7F008280)) #define SERVICE (*((volatile unsigned long *)0x7F008284)) #define SERVICEPEND (*((volatile unsigned long *)0x7F008288)) #define VIC0IRQSTATUS (*((volatile unsigned long *)0x71200000)) #define VIC0FIQSTATUS (*((volatile unsigned long *)0x71200004)) #define VIC0RAWINTR (*((volatile unsigned long *)0x71200008)) #define VIC0INTSELECT (*((volatile unsigned long *)0x7120000c)) #define VIC0INTENABLE (*((volatile unsigned long *)0x71200010)) #define VIC0INTENCLEAR (*((volatile unsigned long *)0x71200014)) #define VIC0PROTECTION (*((volatile unsigned long *)0x71200020)) #define VIC0SWPRIORITYMASK (*((volatile unsigned long *)0x71200024)) #define VIC0PRIORITYDAISY (*((volatile unsigned long *)0x71200028)) #define VIC0ADDRESS (*((volatile unsigned long *)0x71200f00)) #define PWMTIMER_BASE (0x7F006000) #define TCFG0 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x00)) ) #define TCFG1 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x04)) ) #define TCON ( *((volatile unsigned long *)(PWMTIMER_BASE+0x08)) ) #define TCNTB0 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x0C)) ) #define TCMPB0 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x10)) ) #define TCNTO0 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x14)) ) #define TCNTB1 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x18)) ) #define TCMPB1 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x1C)) ) #define TCNTO1 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x20)) ) #define TCNTB2 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x24)) ) #define TCMPB2 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x28)) ) #define TCNTO2 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x2C)) ) #define TCNTB3 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x30)) ) #define TCMPB3 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x34)) ) #define TCNTO3 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x38)) ) #define TCNTB4 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x3C)) ) #define TCNTO4 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x40)) ) #define TINT_CSTAT ( *((volatile unsigned long *)(PWMTIMER_BASE+0x44)) ) void irq_init(void) { /* 在中断控制器里使能timer0中断 */ VIC0INTENABLE |= (1<<23); } // timer0中断的中断处理函数 void do_irq() { static int i=1; printf("%d Timer0 interrupt occur\r\n",i++); unsigned long uTmp; //清timer0的中断状态寄存器 uTmp = TINT_CSTAT; TINT_CSTAT = uTmp; } // 初始化timer void timer_init(unsigned long utimer,unsigned long uprescaler,unsigned long udivider,unsigned long utcntb,unsigned long utcmpb) { unsigned long temp0; // 定时器的输入时钟 = PCLK / ( {prescaler value + 1} ) / {divider value} = PCLK/(65+1)/16=62500hz //设置预分频系数为66 temp0 = TCFG0; temp0 = (temp0 & (~(0xff00ff))) | ((uprescaler-1)<<0); TCFG0 = temp0; // 16分频 temp0 = TCFG1; temp0 = (temp0 & (~(0xf<<4*utimer))& (~(1<<20))) |(udivider<<4*utimer); TCFG1 = temp0; // 1s = 62500hz TCNTB0 = utcntb; TCMPB0 = utcmpb; // 手动更新 TCON |= 1<<1; // 清手动更新位 TCON &= ~(1<<1); // 自动加载和启动timer0 TCON |= (1<<0)|(1<<3); // 使能timer0中断 temp0 = TINT_CSTAT; temp0 = (temp0 & (~(1<<utimer)))|(1<<(utimer)); TINT_CSTAT = temp0; }
相关文章推荐
- tiny6410裸机实验第2章--------------点亮LED灯(原理和代码分析)
- 第十天: 定时器、看门狗、PWM、蜂鸣器、RTC原理及代码实战
- tiny6410裸机实验第8章--------------中断(原理及代码)
- 数据压缩原理实验5_JPEG编解码原理及代码分析
- pwm驱动原理和代码实现
- 编译原理实验,实现一个代码解析程序
- cortex_m3_stm32嵌入式学习笔记(九):PWM 输出实验(定时器的PWM输出)
- 【iCore3 双核心板】例程八:定时器PWM实验——呼吸灯
- tiny6410裸机实验第6章--------------NAND(初始化原理)
- 基于Wolf32F031 自由评估板的Buzzer(PWM控制方式)实验硬件原理及软件API使用方法(适用于STM32F030/031)
- 单片机定时器中断原理和C语言代码详解
- C51单片机中断,寄存器,定时器,PWM原理,配置及使用
- 我在研究Photoshop浮雕效果做实验时,无意中写了一段代码,经过几天的改进和原理论证,我觉得该浮雕效果从原理上是说得通的,应该有一定的应用价值,故发表在我的BLOG上,希望大家能提出改进意见:
- 【iCore4 双核心板_ARM】例程八:定时器PWM实验——呼吸灯
- 单片机定时器中断原理和C语言代码详解
- 基于Wolf32F031 自由评估板的Buzzer(PWM控制方式)实验硬件原理及软件API使用方法(适用于STM32F030/031)
- tiny6410裸机实验第5章--------------DDR(代码重定位)
- tiny6410裸机实验第5章--------------DDR(代码重定位)
- tiny6410裸机实验第9章--------------LCD(原理及源代码)
- tiny6410裸机实验第5章--------------DDR(初始化原理)