51单片机PWM调速时遇到的问题,哪位大神帮我看看!
时间:10-02
整理:3721RD
点击:
下面是单片机PWM调速直流电机的程序,PWMOUT连接P2.4端口作为PWM输出口,依照程序,当温度在30度以下时,应该输出低电平,但是proteus仿真中却输出了方波,是为什么?
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
unsigned char HighRH = 0; //高电平重载值的高字节
unsigned char HighRL = 0; //高电平重载值的低字节
unsigned char LowRH = 0; //低电平重载值的高字节
unsigned char LowRL = 0; //低电平重载值的低字节
sbit PWMOUT=P2^4;
sbit DQ=P1^0;
uint tvalue; //温度值
uchar tflag; //温度正负标志
/**********测温模块************/
void delay_18B20(unsigned int i) //延时1微秒
{
while(i--);
}
void ds1820rst() /*ds1820复位*/
{
unsigned char x=0;
DQ = 1; //DQ复位
delay_18B20(4); //延时
DQ = 0; //DQ拉低
delay_18B20(100); //精确延时大于 480us
DQ = 1; //拉高
delay_18B20(40);
}
uchar ds1820rd() /*读数据*/
{
unsigned char i=0;
unsigned char dat = 0;
for (i=8;i>0;i--)
{
DQ = 0; //给脉冲信号
dat>>=1;
DQ = 1; //给脉冲信号
if(DQ) dat|=0x80;
delay_18B20(10);
}
return(dat);
}
void ds1820wr(uchar wdata) /*写数据*/
{
unsigned char i=0;
for (i=8; i>0; i--)
{
DQ = 0;
DQ = wdata&0x01;
delay_18B20(10);
DQ = 1;
wdata>>=1;
}
}
read_temp() /*读取温度值并转换*/
{
uchar a,b;
ds1820rst();
ds1820wr(0xcc); // 跳过读序列号
ds1820wr(0x44); // 启动温度转换
ds1820rst();
ds1820wr(0xcc); // 跳过读序列号
ds1820wr(0xbe); // 读取温度
a=ds1820rd();
b=ds1820rd();
tvalue=b;
tvalue<<=8;
tvalue=tvalue|a;
if(tvalue<0x0fff)
tflag=0;
else
{
tvalue=~tvalue+2; tflag=1; //负温度
}
tvalue=tvalue*(0.625); //温度值扩大10倍,精确到1位小数
return(tvalue);
}
/***********温度显示模块*********/
unsigned char code str[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00,0x40} ; //共阴数码管字码表
unsigned char code wei[]={0x0f2,0x0f1}; //位选信号
uchar data disdata[5];
void ds1820disp() //温度值显示
{
uchar i;
disdata[0]=tvalue/1000; //百位数
disdata[1]=tvalue%1000/100; //十位数
disdata[2]=tvalue%100/10; //个位数
disdata[3]=tvalue%10; //小数位
for(i=0;i<150;i++)
{P2=wei[0];
P0=str[disdata[1]];
delay_18B20(20);
P2=wei[1];
P0=str[disdata[2]];
delay_18B20(20);
}
}
void ConfigPWM(unsigned int fr, unsigned char dc);
void ClosePWM();
void main(){
while (1){
read_temp();
ds1820disp();
if(tvalue>=300)
if(tvalue>=500)
ClosePWM();
else
ConfigPWM(100,50);
else
PWMOUT=0;
}
}
/* 配置并启动 PWM,fr-频率,dc-占空比 */
void ConfigPWM(unsigned int fr, unsigned char dc){
unsigned int high, low;
unsigned long tmp;
tmp = (11059200/12) / fr; //计算一个周期所需的计数值
tmp = tmp/fr;
high = (tmp*dc) / 100; //计算高电平所需的计数值
low = tmp - high; //计算低电平所需的计数值
high = 65536 - high + 12; //计算高电平的重载值并补偿中断延时
low = 65536 - low + 12;//计算低电平的重载值并补偿中断延时
HighRH = (unsigned char)(high>>8); //高电平重载值拆分为高低字节
HighRL = (unsigned char)high;
LowRH = (unsigned char)(low>>8); //低电平重载值拆分为高低字节
LowRL = (unsigned char)low;
TMOD &= 0xF0; //清零 T0 的控制位
TMOD |= 0x01; //配置 T0 为模式 1
TH0 = HighRH; //加载 T0 重载值
TL0 = HighRL;
ET0 = 1; //使能 T0 中断
TR0 = 1; //启动 T0
EA=1;
PWMOUT = 1; //输出高电平
}
/* 关闭 PWM */
void ClosePWM(){
TR0 = 0; //停止定时器
ET0 = 0; //禁止中断
PWMOUT = 1; //输出高电平
}
/* T0 中断服务函数,产生 PWM 输出 */
void InterruptTimer0() interrupt 1{
if (PWMOUT == 1){ //当前输出为高电平时,装载低电平值并输出低电平
TH0 = LowRH;
TL0 = LowRL;
PWMOUT = 0;
}else{ //当前输出为低电平时,装载高电平值并输出高电平
TH0 = HighRH;
TL0 = HighRL;
PWMOUT = 1;
}
}
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
unsigned char HighRH = 0; //高电平重载值的高字节
unsigned char HighRL = 0; //高电平重载值的低字节
unsigned char LowRH = 0; //低电平重载值的高字节
unsigned char LowRL = 0; //低电平重载值的低字节
sbit PWMOUT=P2^4;
sbit DQ=P1^0;
uint tvalue; //温度值
uchar tflag; //温度正负标志
/**********测温模块************/
void delay_18B20(unsigned int i) //延时1微秒
{
while(i--);
}
void ds1820rst() /*ds1820复位*/
{
unsigned char x=0;
DQ = 1; //DQ复位
delay_18B20(4); //延时
DQ = 0; //DQ拉低
delay_18B20(100); //精确延时大于 480us
DQ = 1; //拉高
delay_18B20(40);
}
uchar ds1820rd() /*读数据*/
{
unsigned char i=0;
unsigned char dat = 0;
for (i=8;i>0;i--)
{
DQ = 0; //给脉冲信号
dat>>=1;
DQ = 1; //给脉冲信号
if(DQ) dat|=0x80;
delay_18B20(10);
}
return(dat);
}
void ds1820wr(uchar wdata) /*写数据*/
{
unsigned char i=0;
for (i=8; i>0; i--)
{
DQ = 0;
DQ = wdata&0x01;
delay_18B20(10);
DQ = 1;
wdata>>=1;
}
}
read_temp() /*读取温度值并转换*/
{
uchar a,b;
ds1820rst();
ds1820wr(0xcc); // 跳过读序列号
ds1820wr(0x44); // 启动温度转换
ds1820rst();
ds1820wr(0xcc); // 跳过读序列号
ds1820wr(0xbe); // 读取温度
a=ds1820rd();
b=ds1820rd();
tvalue=b;
tvalue<<=8;
tvalue=tvalue|a;
if(tvalue<0x0fff)
tflag=0;
else
{
tvalue=~tvalue+2; tflag=1; //负温度
}
tvalue=tvalue*(0.625); //温度值扩大10倍,精确到1位小数
return(tvalue);
}
/***********温度显示模块*********/
unsigned char code str[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00,0x40} ; //共阴数码管字码表
unsigned char code wei[]={0x0f2,0x0f1}; //位选信号
uchar data disdata[5];
void ds1820disp() //温度值显示
{
uchar i;
disdata[0]=tvalue/1000; //百位数
disdata[1]=tvalue%1000/100; //十位数
disdata[2]=tvalue%100/10; //个位数
disdata[3]=tvalue%10; //小数位
for(i=0;i<150;i++)
{P2=wei[0];
P0=str[disdata[1]];
delay_18B20(20);
P2=wei[1];
P0=str[disdata[2]];
delay_18B20(20);
}
}
void ConfigPWM(unsigned int fr, unsigned char dc);
void ClosePWM();
void main(){
while (1){
read_temp();
ds1820disp();
if(tvalue>=300)
if(tvalue>=500)
ClosePWM();
else
ConfigPWM(100,50);
else
PWMOUT=0;
}
}
/* 配置并启动 PWM,fr-频率,dc-占空比 */
void ConfigPWM(unsigned int fr, unsigned char dc){
unsigned int high, low;
unsigned long tmp;
tmp = (11059200/12) / fr; //计算一个周期所需的计数值
tmp = tmp/fr;
high = (tmp*dc) / 100; //计算高电平所需的计数值
low = tmp - high; //计算低电平所需的计数值
high = 65536 - high + 12; //计算高电平的重载值并补偿中断延时
low = 65536 - low + 12;//计算低电平的重载值并补偿中断延时
HighRH = (unsigned char)(high>>8); //高电平重载值拆分为高低字节
HighRL = (unsigned char)high;
LowRH = (unsigned char)(low>>8); //低电平重载值拆分为高低字节
LowRL = (unsigned char)low;
TMOD &= 0xF0; //清零 T0 的控制位
TMOD |= 0x01; //配置 T0 为模式 1
TH0 = HighRH; //加载 T0 重载值
TL0 = HighRL;
ET0 = 1; //使能 T0 中断
TR0 = 1; //启动 T0
EA=1;
PWMOUT = 1; //输出高电平
}
/* 关闭 PWM */
void ClosePWM(){
TR0 = 0; //停止定时器
ET0 = 0; //禁止中断
PWMOUT = 1; //输出高电平
}
/* T0 中断服务函数,产生 PWM 输出 */
void InterruptTimer0() interrupt 1{
if (PWMOUT == 1){ //当前输出为高电平时,装载低电平值并输出低电平
TH0 = LowRH;
TL0 = LowRL;
PWMOUT = 0;
}else{ //当前输出为低电平时,装载高电平值并输出高电平
TH0 = HighRH;
TL0 = HighRL;
PWMOUT = 1;
}
}
最好给出完整的程序
已经是完整的程序了
最近也开始学习pwm了
进来看看,学习学习
我才学到定时器的章节
给出完整的程序
注意中断的优先级而且在中断内尽量少写程序,中断是有时间的,而且是定时器0的中断