计算机控制技术实验说明
编程实验分别仿真和实验台操作两种方式。
实验1 AD转换--输入
AD转换是所有嵌入式系统或机器人获取外部信息的一种重要方式,将温度、角度和位置等转换为对应的数字量,供处理器处理。
原理图:
程序:
/*************** ex1 ******************/ #include <reg52.h> #define uint unsigned int #define uchar unsigned char uchar code LEDData[]= { 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f }; sbit OE = P1^0; sbit EOC = P1^1; sbit ST = P1^2; sbit CLK = P1^3; void DelayMS(uint ms) { uchar i; while(ms--) { for(i=0;i<120;i++); } } void Display_Result(uchar d) { P2 = 0xf7; P0 = LEDData[d%10]; DelayMS(5); P2 = 0xfb; P0 = LEDData[d%100/10]; DelayMS(5); P2 = 0xfd; P0 = LEDData[d/100]; DelayMS(5); } void main() { TMOD = 0x02; TH0 = 0x14; TL0 = 0x00; IE = 0x82; TR0 = 1; P1 = 0x3f; while(1) { ST = 0; ST = 1; ST = 0; while(EOC == 0); OE = 1; Display_Result(P3); OE = 0; } } void Timer0_INT() interrupt 1 { CLK = !CLK; }如果加入报警功能,低于或超过亮灯报警如下:
实验台,测量电压值并显示:
代码:
//模数实验 #include "reg52.h" #define uint unsigned int #define uchar unsigned char #define ulong unsigned long sbit LE1=P3^3; //定义数值显示 uchar code xianshi[11]={0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xbE,0xE0,0xFE,0xF6,0x00}; sbit ST=P3^0; //起始 sbit OE=P3^1; //使能 sbit EOC=P3^2; //转换完成标志位 sbit ADD_A=P3^5; //输入端口选择A sbit ADD_B=P3^6; //输入端口选择B sbit ADD_C=P3^7; //输入端口选择C uint getdata,average,n,volt,sum; //变量 void delay1_ms(uint time) //延时 { uint i,j; for(i=0;i<time;i++) for(j=0;j<123;j++); } void display_num1(uint dat,uchar num1) //显示数值 { // P2=0x00; // P0=0x00; P0=xianshi[dat]; switch(num1) { case 1: P2=0x01;break; case 2: P2=0x02;break; case 3: P2=0x04;break; case 4: P2=0x08;break; case 5: P2=0x10;break; case 6: P2=0x20;break; case 7: P2=0x40;break; case 8: P2=0x80;break; default: break; } delay1_ms(1); //P0=0x00; } //数码管4位显示函数 void display_num4(uint num) { uint wan; uint qian; uint bai; uint shi; uint ge; P2=0x00; wan=(num/10000)%10; if(wan==0) wan=10; display_num1(wan,5); qian=(num/1000)%10; if(wan==10&&qian==0) qian=10; display_num1(qian,4); bai=(num/100)%10; if(wan==10&&qian==10&&bai==0) bai=10; display_num1(bai,3); shi=(num/10)%10; if(wan==10&&qian==10&&bai==10&&shi==0) shi=10; display_num1(shi,2); ge=num%10; display_num1(ge,1); } void delay(uint N) { while(N--); } uint adconvert_date() { ST=0; ST=1; delay(2); ST=0; while(!EOC); OE=1; delay(2); getdata=P1; delay(2); OE=0; return getdata; } void main() { uint i; uint n; uint volt; ulong sum=0; uint average; P2=0x00; ADD_A=0; ADD_B=0; ADD_C=0; delay(1000); while(1) { ADD_A=0; ADD_B=0; ADD_C=0; ST=0; P2=0x00; for(n=0;n<10;n++) { volt=adconvert_date(); //测量可变电阻电压 sum += volt; //累加次数50 } average=sum/10; //取平均值 average=average*19.4; //换算成电压值 19.4=OK sum=0; //和清零 for(i=0;i<400;i++) display_num4(average); //显示平均值 } }
实验2 DA转换--输出
DA转换将控制器结果转为模拟量控制外部设备。最常用的实验是波形仿真。
数字调压:
代码:
#include <reg52.h> #define uint unsigned int #define uchar unsigned char sbit K1 = P3^0; sbit K2 = P3^1; sbit K3 = P3^2; sbit K4 = P3^3; sbit K5 = P3^4; sbit K6 = P3^5; sbit K7 = P3^6; sbit K8 = P3^7; void DelayMS(uint ms) { uchar i; while(ms--) { for(i=0;i<120;i++); } } void main() { P2 = 0x00; while(1) { if(K1 == 0) P2 = 0; if(K2 == 0) P2 = 35; if(K3 == 0) P2 = 70; if(K4 == 0) P2 = 105; if(K5 == 0) P2 = 140; if(K6 == 0) P2 = 175; if(K7 == 0) P2 = 210; if(K8 == 0) P2 = 255; DelayMS(2); } }波形模拟:
代码:
#include <reg52.h> #include <absacc.h> #define uint unsigned int #define uchar unsigned char #define DAC0832 XBYTE[0xfffe] char code sin_data[256]={0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,0x98,0x9c,0x9f,0xa2,0xa5,0xa8, 0xab,0xae,0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5, 0xd8,0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf4, 0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,0xf6,0xf5, 0xf3,0xf2,0xf0,0xef,0xed,0xec,0xea,0xe8,0xe6,0xe4,0xe3,0xe1,0xde,0xdc,0xda,0xd8,0xd6, 0xd3,0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb4,0xb1,0xae,0xab,0xa8, 0xa5,0xa2,0x9f,0x9c,0x99,0x96,0x92,0x8f,0x8c,0x89,0x86,0x83,0x80,0x7d,0x79,0x76,0x73, 0x70,0x6d,0x6a,0x67,0x64,0x61,0x5e,0x5b,0x58,0x55,0x52,0x4f,0x4c,0x49,0x46,0x43,0x41, 0x3e,0x3b,0x39,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27,0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19, 0x17,0x15,0x14,0x12,0x10,0xf,0xd,0xc,0xb,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x3,0x2,0x1,0x1, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x3,0x3,0x4,0x5,0x6,0x7,0x8, 0x9,0xa,0xc,0xd,0xe,0x10,0x12,0x13,0x15,0x17,0x18,0x1a,0x1c,0x1e,0x20,0x23,0x25,0x27, 0x29,0x2c,0x2e,0x30,0x33,0x35,0x38,0x3b,0x3d,0x40,0x43,0x46,0x48,0x4b,0x4e,0x51,0x54, 0x57,0x5a,0x5d,0x60,0x63,0x66,0x69,0x6c,0x6f,0x73,0x76,0x79,0x7c};//正弦码表,可通过SIN()函数获得 void DelayMS(uint ms) { uchar i; while(ms--) { for(i=0;i<120;i++); } } void delay_nus(unsigned int i) { unsigned int j; while(i--) { for(j=0;j<127;j++); } } /**********************************************/ void delay(unsigned char i) { unsigned char t; for(t=0;t<i;t++); } /********************************************** 输出数据到端口(注意考虑延时) **********************************************/ void conversion(unsigned char out_data) { DAC0832 =out_data; //输出数据 delay(1); //delay_nus(10); //延时等待转换 } /************************************************ 产生正弦波函数 ************************************************/ void sine(void) { unsigned char i; for(i=0;i<255;i++) { conversion(sin_data[i]); } } /*********************************************** 产生锯齿波(下降型) ***********************************************/ void saw(void) { unsigned char j; for(j=0;j<255;j++) conversion(j); } /*********************************************** 产生方波(脉冲) ***********************************************/ void pulse(void) { conversion(0xff); delay_nus(1000); conversion(0x00); delay_nus(1000); } /*********************************************** 产生三角波 ***********************************************/ void triangle(void) { unsigned char k; for(k=0;k<255;k++) conversion(k); for(;k>0;k--) conversion(k); } void main() { while(1) { // pulse(); // saw(); // sine(); triangle(); } }实验台:
代码:
#include"reg52.h" char code sin_data[256]={0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,0x98,0x9c,0x9f,0xa2,0xa5,0xa8, 0xab,0xae,0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5, 0xd8,0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf4, 0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,0xf6,0xf5, 0xf3,0xf2,0xf0,0xef,0xed,0xec,0xea,0xe8,0xe6,0xe4,0xe3,0xe1,0xde,0xdc,0xda,0xd8,0xd6, 0xd3,0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb4,0xb1,0xae,0xab,0xa8, 0xa5,0xa2,0x9f,0x9c,0x99,0x96,0x92,0x8f,0x8c,0x89,0x86,0x83,0x80,0x7d,0x79,0x76,0x73, 0x70,0x6d,0x6a,0x67,0x64,0x61,0x5e,0x5b,0x58,0x55,0x52,0x4f,0x4c,0x49,0x46,0x43,0x41, 0x3e,0x3b,0x39,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27,0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19, 0x17,0x15,0x14,0x12,0x10,0xf,0xd,0xc,0xb,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x3,0x2,0x1,0x1, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x3,0x3,0x4,0x5,0x6,0x7,0x8, 0x9,0xa,0xc,0xd,0xe,0x10,0x12,0x13,0x15,0x17,0x18,0x1a,0x1c,0x1e,0x20,0x23,0x25,0x27, 0x29,0x2c,0x2e,0x30,0x33,0x35,0x38,0x3b,0x3d,0x40,0x43,0x46,0x48,0x4b,0x4e,0x51,0x54, 0x57,0x5a,0x5d,0x60,0x63,0x66,0x69,0x6c,0x6f,0x73,0x76,0x79,0x7c};//正弦码表,可通过SIN()函数获得 void delay_nus(unsigned int i) { unsigned int j; while(i--) { for(j=0;j<127;j++); } } /**********************************************/ void delay(unsigned char i) { unsigned char t; for(t=0;t<i;t++); } /********************************************** 输出数据到端口(注意考虑延时) **********************************************/ void conversion(unsigned char out_data) { P0=out_data; //输出数据 delay(5); //delay_nus(10); //延时等待转换 } /************************************************ 产生正弦波函数 ************************************************/ void sine(void) { unsigned char i; for(i=0;i<255;i++) { conversion(sin_data[i]); } } /*********************************************** 产生锯齿波(下降型) ***********************************************/ void saw(void) { unsigned char j; for(j=0;j<255;j++) conversion(j); } /*********************************************** 产生方波(脉冲) ***********************************************/ void pulse(void) { conversion(0xff); delay_nus(1000); conversion(0x00); delay_nus(1000); } /*********************************************** 产生三角波 ***********************************************/ void triangle(void) { unsigned char k; for(k=0;k<255;k++) conversion(k); for(;k>0;k--) conversion(k); } void main() { while(1) { pulse(); //saw(); //sine(); //triangle(); } }
实验3 电机实验--控制
实验台:
代码:
#include"reg52.h" #include "math.h" #define uchar unsigned char #define uint unsigned int uchar code xianshi[12]={0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xbE,0xE0,0xFE,0xF6,0x9c,0x00}; sbit PWM=P1^7; sbit key1=P1^0; sbit key2=P1^1; sbit key3=P1^2; uint wide=100;//脉宽计数 uint t1=0; //低电平脉宽 uint t2=0; //一个周期 uint time_low=0; uint time_high=100; bit high_flag=0; bit low_flag=0; bit state_flag=0; uint set_count=100;//设定转速值 uint run_count=0;//实际频率的读取 uint stop_count=0; //电机转速存储变量 uint time=0; int en=0,en_1=0,en_2=0; //定义 三个时刻的误差存储变量 float a0=1.7,a1=0.30,a2 =0.002,un=0; //定义PID计算参公式的参数 void delay1_ms(uint time); void delay(uint time); void display_num1(uint dat,uchar num1); void display_num4(uint num); void time01_initiat(void); void key_precess(void); void pid(void); void main() { time01_initiat(); //初始化定时器0和定时器1 while(1) { key_precess(); //键盘扫描函数 } } //1ms延时函数 void delay1_ms(uint time) { uint i,j; for(i=0;i<time;i++) for(j=0;j<123;j++); } //指定的位上显示 指定的一位数据 void display_num1(uint dat,uchar num1) { P0=xianshi[dat]; //段显 switch(num1) { case 1: P2=0x01;break; case 2: P2=0x02;break; case 3: P2=0x04;break; case 4: P2=0x08;break; default: break; } delay1_ms(2); } //四位数据显示函数 void display_num4(uint num) { uint qian; uint bai; uint shi; uint ge; qian=num/1000; if(qian==0)// qian=11; display_num1(11,4); bai=num%1000; bai=bai/100; if(qian==10&&bai==0) bai=10; display_num1(bai,3); shi=num%100; shi=shi/10; if(qian==10&&bai==10&&shi==0) shi=10; display_num1(shi,2); ge=num%10; display_num1(ge,1); } //四位数据显示函数 void display_num4_1(uint num) { uint qian; uint bai; uint shi; uint ge; display_num1(10,4); bai=num%1000; bai=bai/100; if(qian==10&&bai==0) bai=10; display_num1(bai,3); shi=num%100; shi=shi/10; if(qian==10&&bai==10&&shi==0) shi=10; display_num1(shi,2); ge=num%10; display_num1(ge,1); } void delay(uint time) { uint i; for(i=0;i<time&&key1==1;i++) display_num4_1(stop_count); } void delay1(uint num) { uint i; for(i=0;i<num;i++) display_num4(set_count); } void time01_initiat() { TMOD=0X11; //计数器0和定时器1 TL0=0X33; TH0=0XFE;//计数器0赋初值 0.5ms TH1=0X4C; TL1=0X00;//定时器1赋初值 50ms EA=1; PT0=1; ET0=1; ET1=1; TR0=0; TR1=0; IT0=1; EX0=0; } void key_precess() { if(key1==0&&key2==1&&key3==1) //判断系统的运行模式,如果KEY1键 按下 //且state_flag为1则系统处于运行模式,如果state__flag为0则为设置模式 { while(key1==0); state_flag=~state_flag; if(state_flag==1) { EX0=1; TR1=1; TR0=1; en =0; en_1 =0; en_2 =0; un =0; wide=150; //wide = set_count; } } if(key1==1&&key2==0&&key3==1&&state_flag==0) //KEY2为按键加 { //while(key2==0); delay1(20); set_count+=1; if(set_count>300) set_count=100; } if(key1==1&&key2==1&&key3==0&&state_flag==0) //KEY3为按键减 { // while(key3==0); delay1(20); if(set_count>100) set_count-=1; if(set_count==100) set_count=300; } if(state_flag==0) //如果系统处于设置模式,则关闭定时器中断和外部中断,同时初始化部分变量 { PWM = 0; EX0=0; TR0=0; TR1=0; run_count=0; stop_count=0; time=0; t1=0; t2=0; display_num4(set_count); } if(state_flag==1) //如果系统处于运行模式则显示电机的实际转速值 { display_num4_1(stop_count); } } void pid(void) //PID 计算输出量 { en=set_count-stop_count; un=1.7*en-0.03*en_1+0.002*en_2;//计算输出量 if(un > 400)un = 400; if(un <-400)un = -400; en_2=en_1; //更新误差 en_1=en; wide = wide + un/4; //计算wide,用于调节PWM的占空比,计算周期为100ms if(wide>900)wide=900; //防止超限,确保计算饿wide值有效 if(wide<10)wide=10; } //外部中断0用于电机转速测量 void int0() interrupt 0 { EX0=0; run_count++; EX0=1; } //定时器0用于产生PWM ,占空比通过PID计算获得 void time0() interrupt 1 { TL0=0X9c; TH0=0XFF;//计数器0赋初值 100us TR0=0; if(low_flag==0)t1++;//低电平时间计时 t2++; if(t2==1000) //用于确定PWM的周期 ,t2乘以定时器的中断周期即为PWM的周期 { PWM=1; t2=0; low_flag=0; } if(t1==wide)//wide的值即为低电平的时间 { PWM=0; t1=0; low_flag=1; } TR0=1; } void time1() interrupt 3 { TH1=0X3C; TL1=0XBD; //50ms定时 TR1=0; time++; if(time==40) //定时2s到,读取到的值run_count即为电机每秒的转速值 { stop_count=run_count/2; time=0; run_count=0; pid(); //调用PID算法 } TR1=1; }