网站建设怎么翻译,花钱做网站不给部署,常州网络公司中环互联网网站建设,怎么建立网站平台结合按键程序#xff0c;我们设计这样一个功能程序#xff1a;按数字键 1#xff5e;9#xff0c;控制电机转过 1#xff5e;9 圈#xff1b;配合上下键改变转动方向#xff0c;按向上键后正向转 1#xff5e;9 圈#xff0c;向下键则反向转 1#xff5e;9 圈#x…结合按键程序我们设计这样一个功能程序按数字键 19控制电机转过 19 圈配合上下键改变转动方向按向上键后正向转 19 圈向下键则反向转 19 圈左键固定正转 90 度右键固定反转 90Esc 键终止转动。通过这个程序我们也可以进一步体会到如何用按键来控制程序完成复杂的功能以及控制和执行模块之间如何协调工作而你的编程水平也可以在这样的实践练习中得到锻炼和提升。这个程序是第 8 章和本章知识的一个综合——用按键控制步进电机转动。程序中有这么几点值得注意我们分述如下
#include reg52.hsbit KEY_IN_1 P2^4;sbit KEY_IN_2 P2^5;sbit KEY_IN_3 P2^6;sbit KEY_IN_4 P2^7;sbit KEY_OUT_1 P2^3;sbit KEY_OUT_2 P2^2;sbit KEY_OUT_3 P2^1;sbit KEY_OUT_4 P2^0;unsigned char code KeyCodeMap[4][4] { //矩阵按键编号到标准键盘键码的映射表{ 0x31, 0x32, 0x33, 0x26 }, //数字键 1、数字键 2、数字键 3、向上键{ 0x34, 0x35, 0x36, 0x25 }, //数字键 4、数字键 5、数字键 6、向左键{ 0x37, 0x38, 0x39, 0x28 }, //数字键 7、数字键 8、数字键 9、向下键{ 0x30, 0x1B, 0x0D, 0x27 } //数字键 0、ESC 键、 回车键、 向右键};unsigned char KeySta[4][4] { //全部矩阵按键的当前状态{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}};signed long beats 0; //电机转动节拍总数void KeyDriver();void main(){EA 1; //使能总中断TMOD 0x01; //设置 T0 为模式 1TH0 0xFC; //为 T0 赋初值 0xFC67定时 1msTL0 0x67;ET0 1; //使能 T0 中断TR0 1; //启动 T0while (1){KeyDriver(); //调用按键驱动函数}}/* 步进电机启动函数angle-需转过的角度 */void StartMotor(signed long angle){//在计算前关闭中断完成后再打开以避免中断打断计算过程而造成错误EA 0;beats (angle * 4076) / 360; //实测为 4076 拍转动一圈EA 1;}/* 步进电机停止函数 */void StopMotor(){EA 0;beats 0;EA 1;}/* 按键动作函数根据键码执行相应的操作keycode-按键键码 */void KeyAction(unsigned char keycode){static bit dirMotor 0; //电机转动方向//控制电机转动 1-9 圈if ((keycode0x30) (keycode0x39)){if (dirMotor 0){StartMotor(360*(keycode-0x30));}else{StartMotor(-360*(keycode-0x30));}}else if (keycode 0x26){ //向上键控制转动方向为正转dirMotor 0;}else if (keycode 0x28){ //向下键控制转动方向为反转dirMotor 1;}else if (keycode 0x25){ //向左键固定正转 90 度StartMotor(90);}else if (keycode 0x27){ //向右键固定反转 90 度StartMotor(-90);}else if (keycode 0x1B){ //Esc 键停止转动StopMotor();}}/* 按键驱动函数检测按键动作调度相应动作函数需在主循环中调用 */void KeyDriver(){unsigned char i, j;static unsigned char backup[4][4] { //按键值备份保存前一次的值{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}};for (i0; i4; i){ //循环检测 4*4 的矩阵按键for (j0; j4; j){if (backup[i][j] ! KeySta[i][j]){ //检测按键动作if (backup[i][j] ! 0){ //按键按下时执行动作KeyAction(KeyCodeMap[i][j]); //调用按键动作函数}backup[i][j] KeySta[i][j]; //刷新前一次的备份值}}}}/* 按键扫描函数需在定时中断中调用推荐调用间隔 1ms */void KeyScan(){unsigned char i;static unsigned char keyout 0; //矩阵按键扫描输出索引static unsigned char keybuf[4][4] { //矩阵按键扫描缓冲区{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF},{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}};//将一行的 4 个按键值移入缓冲区keybuf[keyout][0] (keybuf[keyout][0] 1) | KEY_IN_1;keybuf[keyout][1] (keybuf[keyout][1] 1) | KEY_IN_2;keybuf[keyout][2] (keybuf[keyout][2] 1) | KEY_IN_3;keybuf[keyout][3] (keybuf[keyout][3] 1) | KEY_IN_4;//消抖后更新按键状态for (i0; i4; i){ //每行 4 个按键所以循环 4 次if ((keybuf[keyout][i] 0x0F) 0x00){//连续 4 次扫描值为 0即 4*4ms 内都是按下状态时可认为按键已稳定的按下KeySta[keyout][i] 0;}else if ((keybuf[keyout][i] 0x0F) 0x0F){//连续 4 次扫描值为 1即 4*4ms 内都是弹起状态时可认为按键已稳定的弹起KeySta[keyout][i] 1;}}//执行下一次的扫描输出keyout; //输出索引递增keyout keyout 0x03; //索引值加到 4 即归零//根据索引释放当前输出引脚拉低下次的输出引脚switch (keyout){case 0: KEY_OUT_4 1; KEY_OUT_1 0; break;case 1: KEY_OUT_1 1; KEY_OUT_2 0; break;case 2: KEY_OUT_2 1; KEY_OUT_3 0; break;case 3: KEY_OUT_3 1; KEY_OUT_4 0; break;default: break;}}/* 电机转动控制函数 */void TurnMotor(){unsigned char tmp; //临时变量static unsigned char index 0; //节拍输出索引unsigned char code BeatCode[8] { //步进电机节拍对应的 IO 控制代码0xE, 0xC, 0xD, 0x9, 0xB, 0x3, 0x7, 0x6};if (beats ! 0){ //节拍数不为 0 则产生一个驱动节拍if (beats 0){ //节拍数大于 0 时正转index; //正转时节拍输出索引递增index index 0x07; //用操作实现到 8 归零beats--; //正转时节拍计数递减}else{ //节拍数小于 0 时反转index--; //反转时节拍输出索引递减index index 0x07; //用操作同样可以实现到-1 时归 7beats; //反转时节拍计数递增}tmp P1; //用 tmp 把 P1 口当前值暂存tmp tmp 0xF0; //用操作清零低 4 位tmp tmp | BeatCode[index]; //用|操作把节拍代码写到低 4 位P1 tmp; //把低 4 位的节拍代码和高 4 位的原值送回 P1}else{ //节拍数为 0 则关闭电机所有的相P1 P1 | 0x0F;}}/* T0 中断服务函数用于按键扫描与电机转动控制 */void InterruptTimer0() interrupt 1{static bit p 0;TH0 0xFC; //重新加载初值TL0 0x67;KeyScan(); //执行按键扫描//用一个静态 bit 变量实现二分频即 2ms 定时用于控制电机p ~p;if (p 1){TurnMotor();}}
针对电机要完成正转和反转两个不同的操作我们并没有使用正转启动函数和反转启动函数这么两个函数来完成也没有在启动函数定义的时候增加一个形式参数来指明其方向。我们这里的启动函数 void StartMotor(signed long angle)与单向正转时的启动函数唯一的区别就是把形式参数 angle 的类型从 unsigned long 改为了 signed long我们用有符号数固有的正负特性来区分正转与反转正数表示正转 angle 度负数就表示反转 angle 度这样处理是不是很简洁又很明了呢而你对有符号数和无符号数的区别用法是不是也更有体会了
针对终止电机转动的操作我们定义了一个单独的 StopMotor 函数来完成尽管这个函数非常简单尽管它也只在 Esc 按键分支内被调用了但我们仍然把它单独提出来作为了一个函数。而这种做法就是基于这样一条编程原则尽可能用单独的函数来完成硬件的某种操作当一个硬件包含多个操作时把这些操作函数组织在一起形成一个对上层的统一接口。这样的层次化处理会使得整个程序条理清晰既有利于程序的调试维护又有利于功能的扩充。
中断函数中要处理按键扫描和电机驱动两件事情而为了避免中断函数过于复杂我们就又分出了按键扫描和电机驱动两个函数这也同样符合上述 2 的编程原则而中断函数的逻辑就变得简洁而清晰了。这里还有个矛盾就是按键扫描我们选择的定时时间是 1ms而本章之前的实例中电机节拍持续时间都是 2ms很显然用 1ms 的定时可以定出 2ms 的间隔而用 2ms 的定时却得不到准确的 1ms 间隔所以我们的做法就是定时器依然定时 1ms然后用一个 bit 变量做标志每 1ms 改变一次它的值而我们只选择值为 1 的时候执行一次动作这样就是 2ms 的间隔了如果我要 3ms、4ms„„呢把 bit 改为 char 或 int 型然后对它们递增判断到哪个值该归零就可以了。这就是在硬件定时器的基础上实现准确的软件定时其实类似的操作我们在讲数码管的时候也用过了回想一下吧。