基于51单片机STC12C5A60S2的PWM软硬件配置
目录
1.PWM简介
2.PWM的软硬件配置
2.1PWM在STC12C5A60S2中的硬件配置
2.2PWM在STC12C5A60S2中的软件配置
1、输出可调频率、固定占空比PWM
2、输出呼吸灯PWM
1.PWM简介
脉宽调制(PWM,Pulse Width Modulation)是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。(百度百科)
PWM是通过脉宽调制来实现控制电压的大小,PWM中有一个重要的参量叫做占空比,占空比的意思就是在一个周期中高电平占整个周期的比例(例如周期为2s,高电平为1s则占空比为50%),实际输出的电压等于输出口电压乘于占空比(例如IO口在高电平输出5V,PWM占空比为50%输出则输出实际电压为5V*50%=2.5V)。PWM在各各领域中都占据非常重要的地位,尤其是电机控制。
2.PWM的软硬件配置
2.1PWM在STC12C5A60S2中的硬件配置
1、配置寄存器
首先我们打开我们STC12C5A60S2的官方中文数据手册,找到第十章PAC/PWM应用。
我们以呼吸灯为例,查看中文手册IO口功能,P1.3口是可以使用PWM输出的,我们以这个IO口为例输出呼吸灯。
那我们要控制多少个寄存器呢,我们可以先打开手册后面的历程
我们所用到的寄存器有CCON、CMOD、CCAPM0、PCA_PWM0、CCAP0L、CCAP0H、CL、CH和CR总共八个寄存器,由于CR寄存器是包含在CCON里面的,实际只需要操作七个寄存器。
下图是所用到的寄存器。
1.1配置CCON寄存器
我们翻回去看到CCON寄存器的格式图
往下翻看到PCA计数器架构图。
要打开计数器,必须开机CR,CR包含寄存器CCON,所以CCON=0X40。
1.2配置CMOD
打开中文手册第十章第一节可以看到寄存器格式图如下
同样的,我们看到PCA计数器架构图。
若要开启计数器必须CIDL置0,配置2分频时钟CPS2、CPS1、CPS0分别为0、0、1,所以CMOD=0X02。
1.3配置CCAPM0
查看中文手册10.2可以看到
我们选择P1.3IO口输出是属于PCA模块0,所以我们配置的寄存器是CCAPM0。在翻过来看到CCAPM0寄存器格式图。
我们往下翻,看到PWM配置的架构图。
若要产生PWM必须开启9位比较器,要开启9位比较器就必须开启ECOMn和PWMn,所以CCAPM0=0x42。
1.4配置PCA_PWM0寄存器
我们看到相应的寄存器
这里的话只有两个位要操控,在下面没有明确说明0是关闭1是打开的情况下,0或1都是可以开启的,这里我们使用0开启,则PCA_PWM0=0x00。
1.5配置CL、CH
我们看到数据手册
这个寄存器是用来保存PCA的装载值的,同样的我们看到PWM架构图。
架构图中,这个寄存器是通过比较器计数存于CL,最后用来与CCPnL进行比较输出的,进行比较之前我们必须置零,CH没有要求我们可写可不写,写的话CH置零,即CH=0、CL=0。
1.6配置寄存器CCAP0H和CCAP0L
我们翻上去看到手册。
我们再看到PWM结构框图。
CCAPnH指向CCAPnL意思就是CCAPnH会自动重装到CCAPnL。后面通过计数器CL计数并与CCPnL比较最后决定输出0或1。到这一步我们很明确的就知道这两个寄存器是控制PWM占空比的,这个寄存器很关键,我们做呼吸灯就是无时无刻的控制占空比来实现。
我们看下手册后面的历程代码怎么配置。
通过注释我们很快了解到,这个数值就是输出占空比为50%的PWM的信号。
这里解释一下为什么CCAP0H = CCAP0L = 0x80 输出的占空比为50%,CCAP计数器CL计满是256,如果 CCAP0H=0X80=128,即计到128时PWM输出管脚翻转,所以 占空比 是128/256=50%。
2、编写相应代码
配置寄存器如下。
void Init_PWM() // PWM功能的初始化
{CMOD = 0X02; // 设置脉冲源CCAPM0 = 0X42; // 开启比较器,允许输出脉宽调制信号PCA_PWM0 = 0X00; // 组成9位比较器,可以设置成1,也可以设置成0CCAP0L = CCAP0H = 0X80; // 比较器中的初值,比较器初值重装CH=0;CL=0; // 装载值为0CCON = 0X40; //开启PAC计数器
}
前面我们说到,如果我们要实现呼吸灯,那么最重要的控制PWM的占空比,并且是时时刻刻都要改变占空比,那么我们就可以通过编写代码时时刻刻改变控制占空比的寄存器(CCAP0H)。
unsigned char dy[15]={16,32,48,64,80,96,112,128,144,160,176,192,208,224,240}; // CCAP0H值的分配,为了实现不同的占空比
我们可以定义一个数组,把256拆成16等份。
void modify_duty()
{u8 i;for(i=0;i<15;i++){CCAP0H = dy[i];delay_ms(100);}for(i=13;i>=1;i--) {CCAP0H = dy[i];delay_ms(100);}
}
每间隔一个delay()时间给CCAP0H装值,上面这个for循环是由低到高,下面的for循环是由高到低,这样就形成了占空比由少变多,再由多变少的过程,实际输出电压就由小到大,再由大到小,这样呼吸灯就完成了。这里的delay是毫秒级的延时,用于控制呼吸周期,延时越大越不丝滑,越小越丝滑。
2.2PWM在STC12C5A60S2中的软件配置
1、输出可调频率、固定占空比PWM
软件输出PWM和硬件输出PWM区别在于软件要靠代码去模拟,所以软件输出PWM算法方面会比较麻烦。我们设定输出可调频率、固定占空比PWM必须要用到定时器,下面教大家怎么利用定时器来输出PWM。
首先我们先配置好定时器,规定其溢出时间(100us)。
void Timer0Init()
{TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。TH0=0XFF; //给定时器赋初值,定时100usTL0=0X9C; ET0=1;//打开定时器0中断允许EA=1;//打开总中断TR0=1;//打开定时器
}
然后我们就可以在定时器的服务函数里面编写我们的算法。
void Timer0() interrupt 1
{static u16 i;TH0=0XFF; //给定时器赋初值,定时100usTL0=0X9C;i++;if(i<PWM_DUTY) P10=1;if((i>PWM_DUTY) && (i<=period)) P10=0;if(i>period) i=0;
}
有些变量是我另外用了一个函数封装。
void PWM(u16 frequency,u16 duty)
{period = 10000/frequency;PWM_DUTY = (duty*period)/100;
}
我们先看到PWM()这个函数,不难理解,变量period就是周期,其计算公式就是1/f,由于计算出来是一个小数,而定时器是一个100us为一个单位的时间变量,所以我们这里要乘上10000使其对等,另外一个变量PWM_DUTY就是占空比变量了,也很简单,公式为(duty*period)/100,这里占空比范围为1~100(精度为1)。
我们再看回定时器中断服务函数,i变量每隔100us加一次,当i小于占空比时间时P10输出1,当i大于占空比时间小于PWM周期时间时P10输出0,每完成一个周期i刷新一次。
很简单,这样我们就完成了使用定时器输出PWM,这样输出PWM是不会干扰主函数上执行的程序的,使得单片机运作更加高效。
2、输出呼吸灯PWM
这个相对于上面的就难多了,难在算法方面,上面固定占空比输出是占空比不变的形式输出,比较好计算出来,这个是时刻变动占空比输出PWM难度大涨。
同样的,我们也需要配置定时器。
void Timer1Init()
{TMOD=0X01;//选择为定时器1模式,工作方式1,仅用TR1打开启动。TH1 = 0xFF; TL1 = 0xff; //1us ET1=1;//打开定时器1中断允许EA=1;//打开总中断TR1=1;//打开定时器
}
在定时器中断服务函数里面我们设置两个变量,用于计算。
void Time1() interrupt 3
{TH1 = 0xFF; TL1 = 0xff; //1ustimer1++; count++;}
呼吸灯算法。
void huxideng()
{if(count>50) { count=0;if(DIR==1) //DIR控制增加或减小{value++;} if(DIR==0){value--;}}if(value==1000){DIR=0;}if(value==0){DIR=1;} if(timer1>1000) //PWM周期为1000*1us{timer1=0;}if(timer1 <value) {P10=1;}else{P10=0;}
}
算法的思路是这样的,让timer1和count两个变量同时在定时器中计数,在函数中再设置一个变量value,count这个变量每计算到50时,判断DIR(0或1)就让value变量加或减一次,然后用timer1变量与value变量进行比较,最后P10输出0或1,DIR变量是决定占空比是增加还是减少的标志量。
我们可以根据程序手画一下占空比图。
假设当占空比变量value自增的情况下我们可以画出
value在自减的情况下我们又可以画出
这样无限循环下去有效电压就可以实现由低到高再有高到低,呼吸灯就实现了。另外提一下,后面的980、960、940us只是个大概数,实际值会比这个大一点,有兴趣的小伙伴可以自己手算一下,这里方便举例就不细算了。
硬件配置.C文件
#include <stc12c5a60s2.h>#define u8 unsigned char
#define u16 unsigned int unsigned char dy[15]={16,32,48,64,80,96,112,128,144,160,176,192,208,224,240}; // CCAP0H值的分配,为了实现不同的占空比void delay_ms(u16 xms)
{u8 j;for(;xms>0;xms--)for(j=110;j>0;j--);
}void Init_PWM() // PWM功能的初始化
{CMOD = 0X02; // 设置脉冲源CCAPM0 = 0X42; // 开启比较器,允许输出脉宽调制信号PCA_PWM0 = 0X00; // 组成9位比较器,可以设置成1,也可以设置成0CCAP0L = CCAP0H = 0X80; // 比较器中的初值,比较器初值重装CH=0;CL=0; // 装载值为0CCON = 0X40; //开启PAC计数器
} void modify_duty()
{u8 i;for(i=0;i<15;i++){CCAP0H = dy[i];delay_ms(100);}for(i=13;i>=1;i--) {CCAP0H = dy[i];delay_ms(100);}
}void main()
{Init_PWM();while(1){modify_duty();}
}
软件配置.C文件
#include <STC12C5A60S2.H>#define u16 unsigned int
#define u8 unsigned charu16 count,value,timer1;
u16 period;
u16 PWM_DUTY;u8 DIR;/*******************************************************************************
可调节频率、占空比固定输出PWM
********************************************************************************/
void Timer0Init()
{TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。TH0=0XFF; //给定时器赋初值,定时100usTL0=0X9C; ET0=1;//打开定时器0中断允许EA=1;//打开总中断TR0=1;//打开定时器
}void Timer0() interrupt 1
{static u16 i;TH0=0XFF; //给定时器赋初值,定时100usTL0=0X9C;i++;if(i<PWM_DUTY) P10=1;if((i>PWM_DUTY) && (i<=period)) P10=0;if(i>period) i=0;
}//第一个入口产量控制频率(范围1~9999HZ),建议不要太大或太小。
//第二个入口产量控制占空比(范围1~100,精度为1)
void PWM(u16 frequency,u16 duty)
{period = 10000/frequency;PWM_DUTY = (duty*period)/100;
}/*******************************************************************************
呼吸灯时刻改变占空比输出PWM
********************************************************************************/
void Timer1Init()
{TMOD=0X01;//选择为定时器1模式,工作方式1,仅用TR1打开启动。TH1 = 0xFF; TL1 = 0xff; //1us ET1=1;//打开定时器1中断允许EA=1;//打开总中断TR1=1;//打开定时器
}void Time1() interrupt 3
{TH1 = 0xFF; TL1 = 0xff; //1ustimer1++; count++;}void huxideng()
{if(count>50) { count=0;if(DIR==1) //DIR控制增加或减小{value++;} if(DIR==0){value--;}}if(value==1000){DIR=0;}if(value==0){DIR=1;} if(timer1>1000) //PWM周期为1000*1us{timer1=0;}if(timer1 <value) {P10=1;}else{P10=0;}
}void main()
{PWM(50,80);Timer0Init();while(1);}
基于51单片机STC12C5A60S2的PWM软硬件配置相关推荐
- 基于51单片机可调PWM发生器
源码:基于51单片机可调PWM发生器 一.设计任务 PWM信号频率范围为20Hz ~ 100kHz 占空比为5%~95% 键盘设置PWM频率和占空比 液晶模块显示输出频率和占空比 二.硬件设计 1.硬 ...
- 104、基于51单片机智能风扇pwm调速红外遥控无线遥控风扇温控风扇系统设计
毕设帮助.开题指导.技术解答(有偿)见文末. 目录 摘要 一.硬件方案 二.设计功能 三.实物图 四.原理图 五.Protues仿真 六.流程图 七.程序源码 八.资料包括 摘要 随着气温的逐渐上升, ...
- 基于51单片机智能台灯pwm调光强光控方案原理图设计
硬件电路的设计 (末尾附文件) 系统的功能分析及体系结构设计 3.1.1系统功能分析 本设计由STC89C52单片机电路+光照检测电路(光敏电阻)+AD0832转换电路+4位高亮LED灯电路+按键电路 ...
- 51单片机的直流电机PWM调速控制系统(附Proteus仿真+C程序等全套资料)
设计思路 直流电机PWM控制系统的主要功能包括:很实现对直流电机的加速.减速以及电机的正转.反转和急停,并且可以调整电机的转速,能够方便的实现电机的智能控制. 主体电路:即直流电机PWM控制模块.这部 ...
- 51单片机声控语音PWM风扇可自动温控定时调速风扇转速显示
实践制作DIY- GC0017-声控语音PWM风扇 一.功能说明: 基于51单片机设计-声控语音PWM风扇 功能介绍: 1.基于51(AT89C52.STC89C52)单片机,DS18B20温度传感器 ...
- 基于51单片机的四路温温控制系统(pt100铂热电阻、PID、PWM)
基于51单片机的四路温度控制系统可以使用PT100铂热电阻作为温度传感器,PID算法进行温度控制,PWM信号输出控制加热器.下面是一个简单的概述: 硬件组成: 51单片机开发板:选择一款带有ADC和P ...
- 基于51单片机直流电机PWM调速设计
具体实现功能 系统由STC89C52单片机.LCD1602液晶显示屏.霍尔测速传感器.3V直流电机.按键模块构成. 具体功能: 1.采用霍尔传感器非接触式测电机转速: 2.LCD1602液晶显示当前的 ...
- 基于51单片机PWM(即脉冲宽度调制)调速数码管显示测速L298M芯片控制直流电机正反运转的项目
基于51单片机PWM(即脉冲宽度调制)调速数码管显示测速L298芯片控制直流电机正反运转的项目 一.前言 1.基于51单片机PWM(即脉冲宽度调制)调速数码管显示测速L298芯片控制直流电机正反运转的 ...
- 基于51单片机的智能鱼缸设计。 有原理图,程序,原文,可代做实物。 才用STC12C5A60S2,最新款国产51单片机
基于51单片机的智能鱼缸设计. 有原理图,程序,原文,可代做实物. 才用STC12C5A60S2,最新款国产51单片机. 本系统设计的主要是基于单片机为核心,设计一款集温度检测.恒温控制.步进电机控制 ...
最新文章
- 疯狂位图之——位图实现12GB无重复大整数集排序
- python小程序-【Python精华】100个Python练手小程序
- 清理无用的CSS样式比较有用的几个工具
- Python编程基础:第三十节 文件检测File Detection
- 教主们:虽然这道题我不会,但Ac还是没问题的。
- 计算机专业买win,新买的电脑是win10系统,有的人却费尽心思重装成win7,为什么呢...
- Daily Report 2012.10.30 刘宇翔
- 【多传感器融合理论】01自动驾驶中常用传感器硬件介绍
- 杨玲 201771010133《面向对象程序设计(java)》第十三周学习总结
- 二、11【FPGA】时序逻辑电路——计数器
- 关于\x开头的字符串编码转换中文解决方法
- 专为球迷准备的免费邮箱
- USB1.1学习笔记
- IT经理的个人宣言:做一个好男人!
- redis 配置文件( IP、端口、密码等信息)
- Ubuntu 16.04下载编译Android11源码
- 天润融通java面试_【天润融通怎么样?】-看准网
- CentOS6.10搜狐浏览器无法切换中文输入法问题之解决
- Android 实验二:Android MVC模式
- flink之SQL入门