课堂作业五
/* main.c 用PWM方波控制直流电机的速度。电机驱动接线及驱动逻辑控制参见"电机测试"例程。 本例程通过主板上K1~K4独立按键,调节PWM占空比,从而调节左右电机转速。 */ #include <reg52.h> #include <PCF8591.h> //定义I/O接口 sbit PWM_IN1 = P1^4; // 高电平1:左电机后退(反转) sbit PWM_IN2 = P1^5; // 高电平1:左电机前进(正转) sbit PWM_IN3 = P1^6; // 高电平1:右电机前进(正转) sbit PWM_IN4 = P1^7; // 高电平1:右电机后退(反转) sbit PWM_EN1 = P1^2; // 高电平1:使能左电机 sbit PWM_EN2 = P1^3; // 高电平1:使能右电机 //前进后退标志位 bit Direction; //为1代表前进,为0代表后退 //sbit KEY1 = P3^4; //定义按键K1,左'+'按键(控制左电机加速),对应核心板上K1 //sbit KEY2 = P3^5; //定义按键K2,左'-'按键(控制左电机减速),对应核心板上K2 //sbit KEY3 = P3^6; //定义按键K3,右'+'按键(控制左电机加速),对应核心板上K3 //sbit KEY4 = P3^7; //定义按键K4,右'+'按键(控制左电机减速),对应核心板上K4 //定义PWM最大级数,也就是调节直流电机的速度等级 #define SPEED_MAX 20 #define HIGH_SPD 10 #define MID_SPD 7 #define LOW_SPD 4 //定义PWM级数,分为0~SPEED_MAX-1级 unsigned char Speed_L; //左电机转速调节(调节PWM的一个周期SPEED_MAX*1ms时间内,左电机正转时间:Speed_L*1ms) unsigned char Speed_R; //右电机转速调节(调节PWM的一个周期SPEED_MAX*1ms时间内,右电机正转时间:Speed_R*1ms) //定义显示缓冲区(由定时中断程序自动扫描) unsigned char DispBuf[8]; //智能小车数码管显示电路 sbit SS = P2^6; //数码管段选信号 sbit CS = P2^7; //数码管位选信号 code unsigned char Tab[] = //共阴极数码管的段码(字形)表 {//定义0123456789AbCdEF的数码管字型数据,其他显示字符需自行计算,如‘-’的字形数据为0x40 0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07, 0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71, }; //计数相关标志位定义 unsigned char sec = 100; //100ms计数 unsigned int counter_1ms = 0; //1ms计数 bit Count_flag = 0; bit Judge_flag = 0; //unsigned char KeyScan(); void DispClear(); void DispInit(); void Delay(unsigned int t); void SysInit(); void main() { //unsigned char k; //关于ADC的定义和赋值 unsigned char light,voltage;//定义中间变量 unsigned char chl2,chl4;//定义中间变量 unsigned char AD_CHANNEL = 0; RST_DS = 0; // 关时钟DS1302 I2C_Init(); SysInit(); // DispBuf[7] = 0x40; //- // DispBuf[6] = Tab[Speed_R / 10]; // DispBuf[5] = Tab[Speed_R % 10]; // DispBuf[4] = 0x40; //- // DispBuf[3] = 0x40; //- // DispBuf[2] = Tab[Speed_L / 10]; // DispBuf[1] = Tab[Speed_L % 10]; // DispBuf[0] = 0x40; //- //PWM_EN1 = 1; //PWM_EN2 = 1; //电机有效 //注:AD/DA中的volt变量即代表AD转化后得到的值 //以下部分需要补充对应值以及判断条件 while(1) { //此处为AD部分 switch(AD_CHANNEL) { case 0: PCF8591_SendByte(AddWr,1); light = PCF8591_RcvByte(AddWr); //ADC0 模数转换1 J8上可接任意电阻元件 break; case 1: PCF8591_SendByte(AddWr,2); chl2 =PCF8591_RcvByte(AddWr); //ADC1 模数转换2 break; case 2: PCF8591_SendByte(AddWr,3); voltage =PCF8591_RcvByte(AddWr); //ADC2 模数转换3 可调电阻SW1 break; case 3: PCF8591_SendByte(AddWr,0); chl4 =PCF8591_RcvByte(AddWr); //ADC3 模数转换4 可调电阻SW2 break; case 4: Pcf8591_DaConversion(AddWr,0, voltage); //DAC 数模转换 break; } if(++AD_CHANNEL > 4) AD_CHANNEL = 0; //AD部分结束 if(light > 200) //此处是光敏传感器经过AD转换后得到的值,需要将其与自己设定的门限值作比较。此处为强光激活 { PWM_EN1 = 1; PWM_EN2 = 1; Count_flag = 1; Judge_flag = 1; break; } Delay(50); } //前2s,高速前进 Direction = 1; Speed_L = HIGH_SPD; Speed_R = HIGH_SPD; while(1) if(sec <= 80) //2s后,中速前进2s { Speed_L = MID_SPD; Speed_R = MID_SPD; break; } while(1) if(sec <= 60) //2s后,低速前进2s { Speed_L = LOW_SPD; Speed_R = LOW_SPD; break; } while(1) if(sec <= 40) //2s后,停车2s { Speed_L = 0; Speed_R = 0; //实际上二者取一即可 break; } while(1) if(sec <= 20) //2s后,低速倒车2s { Direction = 0; Speed_L = MID_SPD; Speed_R = MID_SPD; break; } while(1) if(sec == 0) //倒车完成后,停车并停止计时 { Count_flag = 0; Judge_flag = 0; Speed_L = 0; Speed_R = 0; PWM_EN1 = 0; PWM_EN2 = 0; //break; //此处不break,让程序空转,否则程序重启,计数复位 } /* while(1) { Delay(50); //延时50ms k = KeyScan(); //键盘扫描 if ( k != '\0' ) { switch ( k ) //处理按键 { case 'A': if ( Speed_L < SPEED_MAX-1 ) Speed_L ++; break; case 'B': if ( Speed_L > 0 ) Speed_L --; break; case 'C': if ( Speed_R < SPEED_MAX-1 ) Speed_R ++; break; case 'D': if ( Speed_R > 0 ) Speed_R --; break; default: break; } DispBuf[6] = Tab[Speed_L / 10]; DispBuf[5] = Tab[Speed_L % 10]; DispBuf[2] = Tab[Speed_R / 10]; DispBuf[1] = Tab[Speed_R % 10]; while( KeyScan() != '\0'); //等待松开按键 } } */ } /* 函数:KeyScan() 功能:键盘扫描 返回:扫描到的键值 */ /* unsigned char KeyScan() { unsigned char k; k = '\0'; if ( KEY1 == 0 ) k = 'A'; //k1 左'+' if ( KEY2 == 0 ) k = 'B'; //k2 左'-' if ( KEY3 == 0 ) k = 'C'; //k3 右'+' if ( KEY4 == 0 ) k = 'D'; //k4 右'-' return k; } */ /* 函数:DispClear() 功能:清除数码管的所有显示 */ void DispClear() { unsigned char i; for ( i=0; i<8; i++ ) { DispBuf[i] = 0x00; //8位数码管显示全熄灭 } } /* 函数:DispInit() 功能:数码管扫描显示初始化 */ void DispInit() { DispClear(); //初始为全灭 EA = 0; TH1 = 0xFC; TL1 = 0x66; TR1 = 1; ET1 = 1; EA = 1; } /* 函数:Delay() 功能:延时 说明: 晶振频率为11.0592MHz 延时长度 = 1ms * t */ void Delay(unsigned int t) { unsigned int us_ct; for (;t > 0;t --) //执行代码消耗CPU时间 for (us_ct = 113;us_ct > 0;us_ct --); } /* 函数:SysInit() 功能:系统初始化 */ void SysInit() { TMOD = 0x11; //设置T1为16位定时器 PWM_EN1 = 0; PWM_EN2 = 0; //电机无效 PWM_IN1 = 0; PWM_IN2 = 0; //左电机的停转 PWM_IN3 = 0; PWM_IN4 = 0; //右电机的停转 Speed_L = 0; //设置左电机PWM初值(初始转速) Speed_R = 0; //设置右电机PWM初值 DispInit(); } /* 函数:T1_INT_SVC() 功能:定时器T1的中断服务函数,定时时间1ms */ void T1INTSVC() interrupt 3 { code unsigned char com[] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; //显示位的端口控制字节 static unsigned char n = 0; //n: 扫描显示位计数,0-7 static unsigned char t = 0; TR1 = 0; TH1 = 0xFC; //设置定时器初值0xfc66,对应1ms定时中断时间 TL1 = 0x66; // TR1 = 1; P0 = 0xFF; //消隐(通过控制8位数码管的位控制端,即COM端,让其全不亮) CS = 1; CS = 0; P0 = DispBuf[n]; //更新扫描显示数据 SS = 1; SS = 0; P0 = ~com[n]; //重新显示 CS = 1; CS = 0; n++; //指向下一位扫描显示 n &= 0x07; if(Judge_flag == 1) { t++; if ( t >= SPEED_MAX ) t = 0; //PWM波的周期为:SPEED_MAX*1ms = 20ms if(PWM_EN1 || PWM_EN2) { if(Direction == 1) //小车运动方向为前进 { if ( t < Speed_L ) //PWM波高电平时间:(Speed_L)*1ms { PWM_IN1 = 0; PWM_IN2 = 1; //左电机的正转 } else //PWM波低电平时间:(SPEED_MAX-Speed_L)*1ms { PWM_IN1 = 0; PWM_IN2 = 0; //左电机的停转 } if ( t < Speed_R ) //PWM波高电平时间:Speed_R*1ms { PWM_IN3 = 1; PWM_IN4 = 0; //右电机的正转 } else //PWM波低电平时间:(SPEED_MAX-Speed_R)*1ms { PWM_IN3 = 0; PWM_IN4 = 0; //右电机的停转 } } else if(Direction == 0) //小车运动方向为后退 { if ( t < Speed_L ) //PWM波高电平时间:(Speed_L)*1ms { PWM_IN1 = 1; PWM_IN2 = 0; //左电机的反转 } else //PWM波低电平时间:(SPEED_MAX-Speed_L)*1ms { PWM_IN1 = 0; PWM_IN2 = 0; //左电机的停转 } if ( t < Speed_R ) //PWM波高电平时间:Speed_R*1ms { PWM_IN3 = 0; PWM_IN4 = 1; //右电机的反转 } else //PWM波低电平时间:(SPEED_MAX-Speed_R)*1ms { PWM_IN3 = 0; PWM_IN4 = 0; //右电机的停转 } } } } counter_1ms ++; //1ms加1 if(counter_1ms == 100) { counter_1ms = 0; //0.1s到 if(sec > 0 && Count_flag == 1) sec --; DispBuf[5] = Tab[sec % 10]; //查表取出显示数字对应的段码,存入显示缓冲器数组 DispBuf[6] = Tab[sec / 10 % 10] | 0x80; // "| 0x80"可以使该位带小数点显示 DispBuf[7] = Tab[sec / 100]; DispBuf[0] = Tab[Speed_L % 10]; //查表取出显示数字对应的段码,存入显示缓冲器数组 DispBuf[1] = Tab[Speed_L / 10 % 10] ; // "| 0x80"可以使该位带小数点显示 } }
Work Hard
But do not forget to enjoy life😀
本文来自博客园,作者:YuhangLiuCE,转载请注明原文链接:https://www.cnblogs.com/YuhangLiuCE/p/17782231.html