不是一般的pwm控制,就是几个AD/DA的转换,用三极管放大控制电枢电流..........第一次写这种几百行的大程序感觉好难啊
问题是在proteus上调试发现速度只能加,设置速度比实际速度小的时候就不能降速了,代码也不能发现问题,来求助大家
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
以下是单片机代码
- #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)
|