标题:
才入门的单片机新手请教大家关于直流电机调速的问题
[打印本页]
作者:
256202
时间:
2019-12-31 19:32
标题:
才入门的单片机新手请教大家关于直流电机调速的问题
不是一般的pwm控制,就是几个AD/DA的转换,用三极管放大控制电枢电流..........第一次写这种几百行的大程序感觉好难啊
问题是在proteus上调试发现速度只能加,设置速度比实际速度小的时候就不能降速了,代码也不能发现问题,来求助大家
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
调速.png
(278.03 KB, 下载次数: 37)
下载附件
2019-12-31 19:32 上传
以下是单片机代码
#include <reg52.h>
#define digital P0 //DAC0832 数据管脚
#define leddat P1 //数码管数据管脚
#define en 1 //电机一圈的脉冲数 根据电机实际参数设定
#define uint unsigned int
#define uchar unsigned char
#define ufloat unsigned float
sbit scl=P3^5;
sbit sda=P3^7;
sbit Y3 = P3^0; //数码管段选脚定义
sbit Y2 = P3^1;
sbit Y1 = P3^2;
sbit Y0 = P3^3;
sbit Y7 = P2^0; //数码管段选脚定义
sbit Y6 = P2^1;
sbit Y5 = P2^2;
sbit Y4 = P2^3;
sbit LSA = P2^4; //138译码器管脚定义
sbit LSB = P2^5;
sbit LSC = P2^6;
sbit LSG1 = P2^7;
char code Led_dat[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //共阴数码管段码 0123456789
long double speed=0;
long int count=0; //记录脉冲数量
void Delay10us()
{
unsigned char a,b;
for(b=1;b>0;b--)
for(a=2;a>0;a--);
}
void delay() //延时几微秒。延时函数在很多函数里都要用它。至少要大于4.7us
{;;} //当你把这个函数写在用它这个函数的前面就不用声明了
void init() //初始化总线。将总线都拉高以释放
{
scl=1;
delay(); //I2C总线使用时一般都要延时5us左右
sda=1;
delay();
}
void start() //启始信号。 时钟信号为高电平期间,数据总线产生下降沿。
{ //为什么要下降沿,且sda先要为1。因为先要保证数据线为空才能工作
sda=1; //先释放数据总线。高电平释放
delay();
scl=1;
delay();
sda=0;
delay();
}
void stop()
{
sda=0; //先要有工作状态才能释放,sda=0时在工作状态
delay();
scl=1;
delay();
sda=1; //释放数据总线
delay();
}
void respons() //应答函数
{
uchar i=0;
scl=1; //每个字节发送完后的第九个时钟信号的开始
delay();
while((sda==1)&&(i<255)) //此处i的定义使用了uchar.只要填一个小于255的就行
i++; //此处的sda是从机的
scl=0; //表示主器件默认从器件已经收到而不再等待。不再等待之后,时钟的高电平过了就是低电平,所以scl=0
//此时第酒个时钟信号结束
}
void writebyte(uchar d) //写一字节,每次左移一位
{
uchar i,temp;
temp=d;
for(i=0;i<8;i++)
{
temp=temp<<1;
scl=0; //数据传输期间要想sda可变,先把时钟拉低。此处要给sda赋值
delay();
sda=CY; //CY为左移移入PSW寄存器中的的CY位。
delay();
scl=1; //sda有数据了。保持数据稳定
delay();
}
scl=0; //此处是写数据,是属于数据传输过程中。只有在时钟信号为低电平期间
delay(); //数据总线才可以变化。
sda=1; //所以要想释放数据总线,就必须先把时钟拉低
delay();
/*此处释放总线写在末尾是因为调用它时,前面有起始函数释放了总线*/
}
uchar readbyte()
{
uchar i,k;
scl=0;
delay();
sda=1;
delay();
/*此处释放总线放在前面是因为一般都是先写后读,保险起见,释放一下总线*/
for(i=0;i<8;i++)
{
scl=1; //一个时钟信号的开始
delay();
k=(k<<1)|sda; //实质是把sda的数据,最先传来的放在最高位,依次往下排
scl=0; //一个时钟信号结束
delay();
}
return k;
}
void write(uchar addr,uchar dat)
{
start(); //初始化
writebyte(0x90); //调用写一字节函数.PCF8591为1001。此处是给从机发送写信号(最低位是0)
respons(); //调用应答函数让从机应答
writebyte(addr); //写入地址
respons(); //每写一字节都要应答
writebyte(dat);
respons();
stop();
}
uchar read(uchar addr)
{
uchar dat;
start();
writebyte(0x90); //从此处的发送地址和方向位0到从机
respons(); //此处的从机产生应答。属于“伪写”。用于确定和哪台机子通信
writebyte(addr);
respons();
start();
writebyte(0x91); //从此处开始,从机向主机写数据。读的方向位为1
respons();
dat=readbyte();
stop();
return dat; //读得的数据要返回
}
void delay1(int i) //延时函数
{
while(i--);
}
void display(int x,int y) //数码管操作函数
{
delay1(100);
leddat = ~0x00; //清屏消隐
Y0=0;Y1=1;Y2=1;Y3=1;Y4=1;Y5=1;Y6=1;Y7=1; //段选1
leddat = ~Led_dat[x%10]; //取余数 取出个位数
delay1(100);
leddat = ~0x00;
Y0=1;Y1=0;Y2=1;Y3=1;Y4=1;Y5=1;Y6=1;Y7=1; //段选2
leddat = ~Led_dat[x/10%10]; //取出十位数
delay1(100);
leddat = ~0x00;
Y0=1;Y1=1;Y2=0;Y3=1;Y4=1;Y5=1;Y6=1;Y7=1; //段选3
leddat = ~Led_dat[x/100%10]; //取出百位数
delay1(100);
leddat = ~0x00;
Y0=1;Y1=1;Y2=1;Y3=0;Y4=1;Y5=1;Y6=1;Y7=1; //段选4
leddat = ~Led_dat[x/1000]; //取出千位数
delay1(100);
leddat = ~0x00; //清屏消隐
Y0=1;Y1=1;Y2=1;Y3=1;Y4=0;Y5=1;Y6=1;Y7=1; //段选5
leddat = ~Led_dat[y%10]; //取余数 取出个位数
delay1(100);
leddat = ~0x00;
Y0=1;Y1=1;Y2=1;Y3=1;Y4=1;Y5=0;Y6=1;Y7=1; //段选6
leddat = ~Led_dat[y/10%10]; //取出十位数
delay1(100);
leddat = ~0x00;
Y0=1;Y1=1;Y2=1;Y3=1;Y4=1;Y5=1;Y6=0;Y7=1; //段选7
leddat = ~Led_dat[y/100%10]; //取出百位数
delay1(100);
leddat = ~0x00;
Y0=1;Y1=1;Y2=1;Y3=1;Y4=1;Y5=1;Y6=1;Y7=0; //段选8
leddat = ~Led_dat[y/1000]; //取出千位数
}
void timerInit()
{
TMOD=0x15; //模式设置,00000001
TR0=1; //打开计数器
ET0=1; //开计数器0中断
TR1=1; //打开计数器
ET1=1; //开计数器0中断
TH1=(65536-45872)/256; //50ms
TL1=(65536-45872)%256;
TH0=0;
TL0=0;
EA=1; //开总中断
}
uint T0_read()
{
uchar tl,th1,th2;
uint val;
while(1)
{
th1=TH0;
tl=TL0;
th2=TH0;
if(th1==th2)
break;
}
val=th1*256+tl;
return val;
}
void main()
{
double dat = 0;
int dig=0;
int i;
int x_speed=150; //速度增量
LSA = 0; //138译码器 YC2输出低
LSB = 1;
LSC = 0;
LSG1 = 1;
WR = 0; //打开dac0830转换 WR输出低
timerInit();
while(1)
{
dat=read(0x00);
dat = (dat*67)/255 + 17; //设定的每秒转速 17~84r/s 对应 1020~5040r/min
speed = count/en; //当前速度
if(speed < dat) x_speed+=1; //如果实际速度小于设定速度 速度增量加
else x_speed-=1; //反之则减
if(x_speed > 255)x_speed = 255; //速度增量最大255 最小0
if(x_speed < 0) x_speed = 0;
digital =x_speed; //电机输出速度为 设定速度加上速度增量
i=10;
while(i--)
{
i--;
display(speed*60,dat*60); //显示当前速度 每分钟转速
}
}
}
void timer_T1() interrupt 3 //定时器中断
{
static int i = 0;
TH1=(65536-45872)/256; //50ms
TL1=(65536-45872)%256;
i++;
if(i>=20) //20*50=1000ms 定时1s
{
TR0=0; //关闭计数器 记录脉冲数量
count=T0_read();
TH0=0;
TL0=0;
i=0; //脉冲清零 重新开始计数
TR0=1;
}
}
复制代码
全部资料51hei下载地址:
调速.zip
(115.21 KB, 下载次数: 14)
2019-12-31 19:24 上传
点击文件名下载附件
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1