main.c
#include <reg52.h> #include <function.h>void main(){ // 初始化 u8 TIMES = 50; //【选择舵机】的参数——消抖时间 u8 rudderNum = 0; //【选择舵机】返回值——舵机号 u16 gapTime = 0; //【当前间歇时间】总秒数 u16 gapTempt = 0; u8 gap_min = 0; //【当前间歇时间】分钟 u8 gap_s = 0; //【当前间歇时间】秒 u8 gapNum = 16; //【时停按键矩阵】返回值——修改时间 u8 recard_rudderNum = 0; // 记录上一次的值 u8 recard_gap_min = 0; u8 recard_gap_s = 0; int rotateCount = 0; //【旋转按键】的按下次数 u8 parameter1 = 0; //【数码管显示】参数1 u8 parameter2 = 0; //【数码管显示】参数2 u8 mode_digitalTube = 0; //【数码管显示】模式 u8 flickerNum = 2; //【数码管显示】逻辑切换的闪烁次数 u8 controlNum = 0; //敲定【确认键】or【选择键】 u8 tempRudderNum = 0; u8 angle = 0; u8 angleSign = 0; Init(); while(1) { // 选择舵机 tempRudderNum = SelectKEY_Scan(TIMES); if(tempRudderNum != 0) rudderNum = tempRudderNum; // 时停按键矩阵 if(rudderNum <= 8 && rudderNum >= 1 && mode_digitalTube == 0) gapNum = TimeGapKEY_Scan(TIMES); if(gapNum <= 15 && gapNum >= 0) { gapTempt = gapTime + CountTime(gapNum); if( gapTempt >= 0 && gapTempt <= 1800) // 单次[0, 30]min以内 gapTime += CountTime(gapNum); // 计算时间 gap_min = gapTime/60; gap_s = gapTime%60; // 优先显示分钟逻辑 if(gap_min >= 10) gap_s /= 10; }//if // 旋转角度 if(RotateKEY_Scan(TIMES) == 1 && mode_digitalTube == 1) { rotateCount++; // 计算(参数1-正负)(参数2-十位的数值)的逻辑 if(rotateCount/7 != 0) { rotateCount = -6; } if(rotateCount < 0) { angleSign = 1; angle = -1*rotateCount; } else { angleSign = 0; angle = rotateCount; } }//if // 确认键 <-> 1 和 复位键 <-> 2 controlNum = ControlKEY_Scan(TIMES); if(controlNum != 0) { if(mode_digitalTube == 1) { mode_digitalTube = 0; } else { mode_digitalTube = 1; parameter1 = angleSign; parameter2 = angle; } switch(controlNum) { case 1: { //实现数据保存 Save_InputData(rudderNum, gapTime,angle, angleSign); }break; case 2: { //实现数据恢复默认 Reset_InputData(rudderNum); }break; }//switch }//if if(mode_digitalTube == 0) { parameter1 = gap_min; parameter2 = gap_s; } if(mode_digitalTube == 1) { parameter1 = angleSign; parameter2 = angle; } Display_DigitalTube(rudderNum, parameter1, parameter2, mode_digitalTube); }//while}
function.c
#include <reg52.h> #include <function.h> u8 messageIndex = 0; //【保存数据】s数组的索引u8 MESSAGE[];void Init(){ P2 = 0x00; P3 &= 0x0f; KEY_RO = 0; KEY_OK = 0;}u8 code KEY_TABLE[] ={ 0xEE, 0xDE, 0xBE, 0x7E, 0xED, 0xDD, 0xBD, 0x7D, 0xEB, 0xDB, 0xBB, 0x7B, 0xE7, 0xD7, 0xB7, 0x77};u8 code LedChar[10]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};u8 code LedBuff[4]={0xFF, 0xFF, 0xFF, 0xFF};//初始化数码管显示缓存区// 输入数据的声明struct servoMotorData inputData[8];void Delay_ms(u16 x){ u16 i,j; if(x==1000) { for(i=0;i<19601;i++)//延时1s { for(j=5;j>0;j--); } } else while(x--)for(j=115;j>0;j--);}// 扫描选择舵机的按键 返回舵机编号u8 SelectKEY_Scan(u8 TIMES){ static u8 key_up = 1; if(key_up == 1 && (KEY_S0 == 1||KEY_S1 == 1||KEY_S2 == 1||KEY_S3 == 1||KEY_S4 == 1 ||KEY_S5 == 1 ||KEY_S6== 1||KEY_S7 == 1)) { Delay_ms(TIMES); if(KEY_S0 == 1) return 1; else if(KEY_S1 == 1) return 2; else if(KEY_S2 == 1) return 3; else if(KEY_S3 == 1) return 4; else if(KEY_S4 == 1) return 5; else if(KEY_S5 == 1) return 6; else if(KEY_S6 == 1) return 7; else if(KEY_S7 == 1) return 8; } else if(KEY_S0 == 0&&KEY_S1 == 0 &&KEY_S2 == 0&& KEY_S3 == 0 &&KEY_S4 == 0&& KEY_S5 == 0&& KEY_S6== 0&& KEY_S7 == 0) //检测到松开 key_up = 1; return 0; //无按键按下;}// 时停按键矩阵 返回按键编号u8 TimeGapKEY_Scan(u8 TIMES){ u8 temp, key, key_num; static u8 key_up = 1; P1 = 0Xf0; // 行低列高 // 若高四位不全为1,说明有按键按下 if((P1&0xf0) != 0Xf0 && key_up == 1) { Delay_ms(TIMES); // 消抖 key_up = 0; if((P1&0xf0) != 0Xf0) { temp = P1; // 列检测 P1 = 0x0f; key = temp|P1; for(key_num = 0; key_num < 16; key_num++) if(key == KEY_TABLE[key_num]) break; return key_num; }//if }//if else if((P1&0xf0) == 0Xf0) key_up = 1; return 16; //无键按下,返回16}// 根据按键编号间隔计算时间int CountTime(u8 gapNum){ int addTime = 0; // 加权 switch(gapNum/4) { case 0: addTime = 60; break; case 1: addTime = -60; break; case 2: addTime = 1; break; case 3: addTime = -1; break; } // 赋值 switch(gapNum%4) { case 0: addTime *= 20; break; case 1: addTime *= 10; break; case 2: addTime *= 5; break; case 3: addTime *= 1; break; } return addTime;}// 数码管显示 mode:(0-间隔时间模式)(1-旋转角度模式)void Display_DigitalTube(u8 rudderNum, u8 parameter1, u8 parameter2, u8 mode_digitalTube){ // 先做舵机选择位的显示,再做其他 P3 &= 0x0f; // 先将高四位置0,在修改高四位的值 P3 |= 0x10; P0 = LedChar[rudderNum]; Delay_ms(1); // 间隔时间模式 if(mode_digitalTube == 0) { if(parameter1 < 10 && parameter2 < 10) //a 1.01 { P3 &= 0x0f; P3 |= 0x20; P0 = LedChar[parameter1]&0x7f; //&0x7f —— 点亮小数点 Delay_ms(1); P3 &= 0x0f; P3 |= 0x40; P0 = LedChar[0]; Delay_ms(1); } else if(parameter1 < 10 && parameter2 >= 10) //a1.11 { P3 &= 0x0f; P3 |= 0x20; P0 = LedChar[parameter1]&0x7f; Delay_ms(1); P3 &= 0x0f; P3 |= 0x40; P0 = LedChar[parameter2/10]; Delay_ms(1); } else //a11.1 { P3 &= 0x0f; P3 |= 0x20; P0 = LedChar[parameter1/10]; Delay_ms(1); P3 &= 0x0f; P3 |= 0x40 ; P0 = LedChar[parameter1%10]&0x7f; Delay_ms(1); } // 秒钟的个位代码相同 P3 &= 0x0f; P3 |= 0x80; P0 = LedChar[parameter2%10]; Delay_ms(1); } // 旋转角度模式 else { // 正:舵机号 角度 负:舵机号-角度 P3 &= 0x0f; P3 |= 0x20; if(parameter1 == 1) P0 = 0xbf; //显示负号 if(parameter1 == 0) P0 = 0xff; Delay_ms(1); P3 &= 0x0f; // 显示角度 P3 |= 0x40; P0 = LedChar[parameter2]; Delay_ms(1); P3 &= 0x0f; // 显示0 P3 |= 0x80; P0 = LedChar[0]; Delay_ms(1); }}// 旋转按键u8 RotateKEY_Scan(u8 TIMES){ static u8 key_up = 1; if(KEY_RO == 1 && key_up == 1) { Delay_ms(TIMES); key_up = 0; if(KEY_RO == 1) return 1; } else if(KEY_RO == 0) key_up = 1; return 0; //无按键按下;}// 数码管闪烁反馈void Flicker_DigitalTube(u8 rudderNum, u8 parameter1, u8 parameter2, u8 mode_digitalTube, u8 flickerNum){ for(; flickerNum > 0; flickerNum--) { Display_DigitalTube(rudderNum, parameter1, parameter2, mode_digitalTube); // 四个依次灭掉 P3 &= 0x0f; P3 |= 0x80; P0 = 0xff; Delay_ms(1); P3 &= 0x0f; P3 |= 0x40; P0 = 0xff; Delay_ms(1); P3 &= 0x0f; P3 |= 0x20; P0 = 0xff; Delay_ms(1); P3 &= 0x0f; P3 |= 0x10; P0 = 0xff; Delay_ms(1); }}// 确认键和复位键的扫描u8 ControlKEY_Scan(u8 TIMES){ static u16 times; static key_up = 1; if((KEY_RE == 1 || KEY_OK == 1) && key_up == 1) { times++; //记录进入高电平的时间 if(times >= TIMES) //抖动时间已经过去 { times = 0; if(KEY_OK == 1) return 1; else if(KEY_RE == 1) return 0; } } return 0; //无按键按下;}// 输入数据的保存——核心是依次修改该舵机下的角度和间隔时间void Save_InputData(u8 rudderNum, u16 gapTime, u8 rotateCount, u8 rotateSign){ u8 num; if(rudderNum < 0 || rudderNum >8) return; num = rudderNum - 1; // 角度和间隔时间的赋值 if(inputData[num].gapIndex >= 0 && inputData[num].gapIndex < 4) inputData[num].gapTime[inputData[num].gapIndex++] = gapTime; if(inputData[num].rotateIndex >= 0 && inputData[num].rotateIndex < 3) { // 此处旋转角度不做乘10处理,再另一个单片机上确定真实数据 inputData[num].rotateAngle[inputData[num].rotateIndex++] = rotateCount; if(rotateSign == 1) inputData[num].rotateAngle[inputData[num].rotateIndex] *= -1; }}// 数据复位——核心是一一重置该舵机下的角度和间隔时间void Reset_InputData(u8 rudderNum){ u8 num, i; if(rudderNum < 0 || rudderNum >8) return; num = rudderNum - 1; // 角度和间隔时间的复位 for(i = 0; i < inputData[num].gapIndex; i++) inputData[num].gapTime[i] = 0; for(i = 0; i < inputData[num].rotateIndex; i++) inputData[num].rotateAngle[i] = 0; inputData[num].gapIndex = 0; inputData[num].rotateIndex = 0;}void SendData(){ // 数据写入数组 u16 writeIndex = 0; u8 structIndex = 0; u8 temp_gapIndex = 0; u8 temp_rotateIndex = 0; u8 servoMotorNum = 'A' - 1; //表示1号舵机 u8 i = 0; /* 写入数据格式 A rotateIndex gapTime[] rotateAngle[] B…… */ for(; structIndex < 8; structIndex++) { // 写入舵机号(A~H) servoMotorNum++; MESSAGE[writeIndex++] = servoMotorNum; // 如果此舵机没有数据可写,跳过 temp_rotateIndex = inputData[structIndex].rotateIndex; if(temp_rotateIndex == 0) { structIndex++; continue; } else { /* 此舵机无需旋转时,仅保存舵机字母 若需旋转,第二位表示选择角度个数 timeNum = rotateNum + 1; */ MESSAGE[writeIndex++] = temp_rotateIndex; } // 写入时间 temp_gapIndex = inputData[structIndex].gapIndex; for(; temp_gapIndex > 0; temp_gapIndex--) { i = 0; MESSAGE[writeIndex++] = inputData[structIndex].gapTime[i]; i++; } // 写入角度 temp_rotateIndex = inputData[structIndex].rotateIndex; for(; temp_rotateIndex > 0; temp_rotateIndex--) { i = 0; MESSAGE[writeIndex++] = inputData[structIndex].rotateAngle[i]; i++; } } // 串口初始化 SCON = 0x50;//设置串行口工作方式1,接收控制打开 TMOD |= 0x20;//定时器1设置工作方式2 TH1 = 0xFD;//设置波特率为9600,数据位8,停止位1,无校验位,晶振频率11.0592M TL1 = 0xFD; TR1 = 1;//启动定时器1 // 发送数据 messageIndex = 0; while(MESSAGE[messageIndex] != '\0') { SBUF = MESSAGE[messageIndex];//将一个字符放入串行数据缓冲器SBUF while(!TI);//等待发送中断标志为1 TI = 0;//清除发送中断标志 messageIndex++;//准备下一个字符 } Delay_ms(500);//延时}
function.h
#ifndef __FUNCTION_H__#define __FUNCTION_H__ typedef unsigned char u8;//对数据类型进行声明定义typedef unsigned int u16;typedef unsigned long u32;// 数码管段选-直接对P0口操作// 时停按键矩阵-直接对P1口操作// 定义与选择舵机按键连接的位sbit KEY_S0 = P2^0;sbit KEY_S1 = P2^1;sbit KEY_S2 = P2^2;sbit KEY_S3 = P2^3;sbit KEY_S4 = P2^4;sbit KEY_S5 = P2^5;sbit KEY_S6 = P2^6;sbit KEY_S7 = P2^7;// 数码管位选+其他按键+数据传输sbit KEY_RO = P3^2;sbit KEY_OK = P3^3;sbit KEY_RE = P3^0;sbit DigitalTube_w = P3^4;sbit DigitalTube_x = P3^5;sbit DigitalTube_y = P3^6;sbit DigitalTube_z = P3^7;extern u8 MESSAGE[];//数码管状态值初始化 extern u8 code LedChar[10];extern u8 code LedBuff[4];//舵机结构体extern struct servoMotorData inputData[8];struct servoMotorData{ u16 gapTime[4]; u8 gapIndex; // 记录舵机间歇时间数组的索引 char rotateAngle[3]; u8 rotateIndex; // 记录舵机旋转角度数组的索引}; // 声明在 function.c 中定义的函数void Init();void Delay_ms(u16);u8 SelectKEY_Scan(u8);u8 TimeGapKEY_Scan(u8);int CountTime(u8);void Display_DigitalTube(u8, u8, u8, u8);u8 RotateKEY_Scan(u8);void Flicker_DigitalTube(u8, u8, u8, u8, u8);u8 ControlKEY_Scan(u8);void Save_InputData(u8, u16, u8, u8);void Reset_InputData(u8);void SendData();#endif