完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
用单片机设计一个步进电机控制器。要求能对步进电机实现正、反转及速度控制,同时能对步进电机进行位置控制,即能控制步进电机从一个位置精确地运行到另一个位置。步进电机为四相反应式,软件生成脉冲序列,可设置参数和运行状态参数实时显示。威廉希尔官方网站
要求 1. 转速:0—3000r/m,误差1‰;2. 角位移控制:2º—9999º;3. 方向:可逆;4. 可设置参数和运行状态参数实时显示。
下面是我编写的一个程序和电路原理图,程序中两个问题需要解决:1、我设定的转速和实际的转速并不是一一对应的。2、步进电机的步距角一般都是0.9/1.8和0.75/1.5的,要怎样修改程序才能显示角位移小数部分。麻烦各位高手帮我看看。谢谢了! #include #include void delayNOP() {_nop_();_nop_();_nop_();_nop_();} #define uchar unsigned char #define uint unsigned int ***it LCD_RS = P2^0; ***it LCD_RW = P2^1; ***it LCD_EN = P2^2; uchar keycode,scan1,scan2; uchar chuzhi; uchar shedingzhuansu[4]={0x00,0x01,0x00,0x00}; //存储转速 uchar shedingjiaodu[4]={0x03,0x00,0x00,0x00}; //存储角度 uint zhuanguojiaodu=0,number;//计算转过的角度和脉冲计数 uchar code FFW[8]={0xf1,0xf3,0xf2,0xf6,0xf4,0xfc,0xf8,0xf9}; //反转码 uchar code REV[8]={0xf9,0xf8,0xfc,0xf4,0xf6,0xf2,0xf3,0xf1}; //正传码 uchar m,v=0,q=0; uint zhuansu,jiaodu; //设置的转速和角度 bit zhengrunflag=0,fanrunflag=0,stopflag=0,zhuansushezhiflag=1,jiaodushezhiflag=0,shuzi; //区分控制键和数字键标志 bit on_off=0; //运行与停止标志 bit direction; //正反标志 uint data_temp,data_temP1,data_temp2,data_temp3,data_temp4; void delay(uint t) //延时函数 { uchar k; while(t--) { for(k=0; k<125; k++) { } } } bit lcd_busy() // 检查LCD忙不忙 { bit result; LCD_RS = 0; LCD_RW = 1; LCD_EN = 1; delayNOP(); result = (bit)(P0&0x80); LCD_EN = 0; return(result); } void lcd_wcmd(uchar cmd) // LCD写指令 { while(lcd_busy()); LCD_RS = 0; LCD_RW = 0; LCD_EN = 0; _nop_(); _nop_(); P0 = cmd; delayNOP(); LCD_EN = 1; delayNOP(); LCD_EN = 0; } void lcd_wdat(uchar dat) //LCD写数据 { while(lcd_busy()); LCD_RS = 1; LCD_RW = 0; LCD_EN = 0; P0 = dat; delayNOP(); LCD_EN = 1; delayNOP(); LCD_EN = 0; } void lcd_clr() // LCD清屏 { lcd_wcmd(0x01); delay(5); } void lcd_init() // LCD初始化 { delay(30); lcd_wcmd(0x38); //16*2显示,5*7点阵,8位数据 delay(5); lcd_wcmd(0x38); delay(5); lcd_wcmd(0x38); delay(5); lcd_wcmd(0x0c); //显示开,关光标 delay(5); lcd_wcmd(0x06); //移动光标 delay(5); lcd_wcmd(0x01); //清除LCD的显示内容 delay(5); } uchar keyscan()//矩阵键盘线反转法扫描程序 { uchar i=0; P3=0xf0; scan1=P3; if(scan1!=0xf0) { delay(8); if(scan1!=0xf0) { P3=0x0f; scan2=P3; keycode=(scan1|scan2); switch(keycode) { case 0xee: zhengrunflag=1;shuzi=0;break; case 0xde: fanrunflag=1;shuzi=0;break; case 0xbe: stopflag=1;shuzi=0;break; case 0xed: zhuansushezhiflag=1;shuzi=0;break; case 0xdd: jiaodushezhiflag=1;shuzi=0;break; case 0xbd: chuzhi=0;shuzi=1;break; case 0x7d: chuzhi=1;shuzi=1;break; case 0xeb: chuzhi=2; shuzi=1;break; case 0xdb: chuzhi=3;shuzi=1;break; case 0xbb: chuzhi=4;shuzi=1;break; case 0x7b: chuzhi=5;shuzi=1;break; case 0xe7: chuzhi=6;shuzi=1;break; case 0xd7: chuzhi=7;shuzi=1;break; case 0xb7: chuzhi=8;shuzi=1;break; case 0x77: chuzhi=9;shuzi=1;break; } } else shuzi=0; } else shuzi=0; return shuzi; } void zhuansutiaojie() // 转速调节程序 { uint i, j=0; for(i=0;i<4;i++) { while(!keyscan()) {;} shedingzhuansu[j]=chuzhi; lcd_wcmd(j|0x80); lcd_wdat(shedingzhuansu[j]+0x30); j++; delay(500); } zhuansushezhiflag=0; zhuansu=shedingzhuansu[0]*1000; zhuansu=zhuansu+shedingzhuansu[1]*100; zhuansu=zhuansu+shedingzhuansu[2]*10; zhuansu=zhuansu+shedingzhuansu[3];//设定的转速 } void jiaodutiaojie() // 角度调节 { uint i,j=0; for(i=0;i<4;i++) { while(! keyscan()); {;} shedingjiaodu[j]=chuzhi; lcd_wcmd((0x40+j)|0x80); lcd_wdat(shedingjiaodu[j]+0x30); j++; delay(500); } jiaodushezhiflag=0; jiaodu=shedingjiaodu[0]*1000; jiaodu=jiaodu+shedingjiaodu[1]*100; jiaodu=jiaodu+shedingjiaodu[2]*10; jiaodu=jiaodu+shedingjiaodu[3]; //设置的角度 } void data_conv() // 数据转化函数 { data_temP1=data_temp/1000; data_temP1=data_temP1+0x30; data_temp2=data_temp%1000/100; data_temp2=data_temp2+0x30; data_temp3=data_temp%1000%100/10; data_temp3=data_temp3+0x30; data_temp4=data_temp%10; data_temp4=data_temp4+0x30; } void data_dis() //步进电机显示函数 { data_temp = zhuanguojiaodu; //显示转过角度 data_conv(); lcd_wcmd(0x48|0x80); lcd_wdat(data_temP1); lcd_wcmd(0x49|0x80); lcd_wdat(data_temp2); lcd_wcmd(0x4a|0x80); lcd_wdat(data_temp3); lcd_wcmd(0x4b|0x80); lcd_wdat(data_temp4); } void motor_DR() { if(direction==1) {lcd_wcmd(0x47|0x80); lcd_wdat(0x2b); } else { lcd_wcmd(0x47|0x80); lcd_wdat(0x2d); } } void motor_RUN() // 步进电机运转子程序 { if(on_off==1) { TR0=1; motor_DR(); } else { TR0=0; P1 =0x0f; } } void main() //主程序 { delay(10); lcd_init(); lcd_clr(); lcd_wcmd(0x00|0x80); lcd_wdat(shedingzhuansu[0]+0x30); lcd_wdat(shedingzhuansu[1]+0x30); lcd_wdat(shedingzhuansu[2]+0x30); lcd_wdat(shedingzhuansu[3]+0x30); lcd_wcmd(0x40|0x80); lcd_wdat(shedingjiaodu[0]+0x30); lcd_wdat(shedingjiaodu[1]+0x30); lcd_wdat(shedingjiaodu[2]+0x30); lcd_wdat(shedingjiaodu[3]+0x30); TMOD = 0x01; //T0定时方式1 TL0 = 0x9c; //定时时间为0.1ms TH0 = 0xff; EA = 1; ET0 = 1; P1 = 0x0f; while(1) { keyscan(); if(zhuansushezhiflag==1) // 开始调节速度 { zhuansutiaojie();} if(jiaodushezhiflag==1) //开始调节角度 { jiaodutiaojie();} if(zhengrunflag==1) //正转键 { zhuanguojiaodu=0; number=0; on_off=1; direction=1; motor_RUN(); zhengrunflag=0; } if(fanrunflag==1) // 反转键 { zhuanguojiaodu=0; number=0; on_off=1; direction=0; motor_RUN(); fanrunflag=0; } if(stopflag==1) // 停止键 { on_off=0; motor_RUN(); stopflag=0; } if(zhuanguojiaodu==jiaodu) //判断是否达到了设置角度 { zhuanguojiaodu=0; P1=0x0f; on_off=0; motor_RUN(); } data_dis(); //显示函数 } } void motor_onoff() interrupt 1 //定时器0中断服务程序 { TL0 = 0x9c; TH0 = 0xff; q++; if(q else { q=0; number++; //脉冲计数 zhuanguojiaodu=number*2; //转过角度 if(direction==1) //方向标志 { if(v<8) {P1 = FFW[v];v++; } //取数据,正转 if(v==8) { v=0; } } else { if(v<8) {P1 = REV[v];v++; } //取数据,反转 if(v==8) { v=0; } } //电机转动角度 } }
|
|
相关推荐
1 个讨论
|
|
谢谢分享,好东西
|
|
|
|
|
|
只有小组成员才能发言,加入小组>>
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 20:29 , Processed in 0.800235 second(s), Total 50, Slave 38 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号