51单片机PWM输出
程序员文章站
2022-06-23 20:57:58
PWM输出学期快结束了,51单片机的学习也差不多告一段落,也快要转入新的学习阶段,寒假找个时间看看32,小白哈哈哈,下面是我学习51定时器弄出来的小东西,一个PWM的输出。还请大神指点。刚开始觉得PWM输出应该不难,很容易做的,但是后面越像越多,就感觉其实做不来不难,做精确才难,刚开始想到的用一个定时器做,也就是在中断里面计数,来个中断计数加一,判断到自己想要的值就改变电平,这样做思路简单,但......
PWM输出
学期快结束了,51单片机的学习也差不多告一段落,也快要转入新的学习阶段,寒假找个时间看看32,小白哈哈哈,下面是我学习51定时器弄出来的小东西,一个PWM的输出。还请大神指点。
刚开始觉得PWM输出应该不难,很容易做的,但是后面越像越多,就感觉其实做不来不难,做精确才难,刚开始想到的用一个定时器做,也就是在中断里面计数,来个中断计数加一,判断到自己想要的值就改变电平,这样做思路简单,但有一个坏处,就是有个0.14ms的误差无法消除(可能是我太菜,没找到解决方法),后来就想到用两个定时器做了,定时器0,用来改变周期,定时器1,用来改变占空比,当定时器0来一个中断时,PWM=1,并开启定时器1,定时器1来一个中断时,PWM=0,关闭定时器,至于为什么要关闭定时器1,是因为定时器1的初值比较小,可能在定时器0还没发生中断的时候,就发生几次中断了,所以会影响PWM输出,还有发生中断的时候,有一些时间,和运行的时候有些静态误差,所以在初值哪儿微调。
废话少说,直接上代码。
延时函数
#ifndef __DELAY_H
#define __DELAY_H
#include "reg51.h"
#define uchar unsigned char
#define uint unsigned int
void delay_ms(uint i);
#endif
#include "delay.h"
void delay_ms(uint i)
{
uchar n;
while(i--)
for(n=0;n<120;n++)
;
}
下面直接主函数了
#include "sys.h" //自己写的一个头文件
#include "delay.h"
unsigned int tim0_I; //占空时间
unsigned int tim0_T; //周期
uchar Temp_TH0,Temp_TL0;
uchar Temp_TH1,Temp_TL1;
sbit PWM=P1^0; //输出引脚
sbit key0=P3^2;
sbit key1=P3^3;
sbit key2=P2^0;
sbit key3=P2^1;
void INT_Init_KEY();
void key2_Init();
void key3_Init();
void TIM0_Init_PWM(); //初始化
//sbit LED=P1^0;
void main()
{
// uchar i;
tim0_I=600;
tim0_T=1000;
PWM=0;
TIM0_Init_PWM();
INT_Init_KEY();
while(1)
{
key2_Init();
key3_Init();
delay_ms(10);
}
}
void TIM0_Init_PWM() //定时器0初始化
{
TMOD=0x11; //方式1:为16位定时/计数器
TH0=(uint)(65535-tim0_T)/256; //取低8位 //设置初始值10us
TL0=(uint)(65535-tim0_T)%256; //取低8位
TH1=(uint)(65535-tim0_I)/256;
TL1=(uint)(65535-tim0_I)%256;
TR1=1;
TR0=1;
ET1=1;
TR0=1; //打开定时器0
ET0=1; //打开外部中断
EA=1; //打开总中断
}
void tim0_Int_PWM() interrupt 1 //设定周期
{
// TR0=0; //设置定时器初值期间,关闭定时器
TH0=(uint)(65535-tim0_T+28)/256; //定时器赋值
TL0=(uint)(65535-tim0_T+28)%256; //加28是为了消除静态误差,还有中断反应时间,下面加30也一样
// TR0=1;
PWM=1;
TR1=1;
}
void tim1_Int_PWM() interrupt 3 //占空比
{
TH1=(uint)(65535-tim0_I+30)/256; //定时器赋值
TL1=(uint)(65535-tim0_I+30)%256;
PWM=0;
TR1=0;//需要把定时器1关了,这样它就不会一直跳,让它一个周期内只跳一次
}
void key2_Init() //周期加1
{
if(key2==0)
{
delay_ms(100);
if(key2==0)
{
tim0_T+=1000;
}
}
}
void key3_Init() //周期减1
{
if(key3==0)
{
delay_ms(100);
if(key3==0)
{
if(tim0_T>0)
tim0_T-=1000;
}
}
}
void INT_Init_KEY() //外部中断初始化
{
EA=1;
EX0=1;
EX1=1;
IT0=1;
IT1=1;
PX0=1;
PX1=1;
}
void INT0_KEY0() interrupt 0 //外部中断0 服务程序//占空时间加1
{
delay_ms(10);
if(key0==0)
{
if(tim0_I<tim0_T)
tim0_I+=10;
}
while(!key0) ;
}
void INT1_KEY1() interrupt 2 //外部中断1 服务程序//占空时间减1
{
delay_ms(10);
if(key1==0)
{
if(tim0_I>0)
tim0_I-=10;
}
while(!key1) ;
}
我就一小白,不足之处,还请指出。
本文地址:https://blog.csdn.net/weixin_44017446/article/details/85922851