main.c

  1. #include <reg52.h>
  2. #include <function.h>
  3. void main()
  4. {
  5. // 初始化
  6. u8 TIMES = 50; //【选择舵机】的参数——消抖时间
  7. u8 rudderNum = 0; //【选择舵机】返回值——舵机号
  8. u16 gapTime = 0; //【当前间歇时间】总秒数
  9. u16 gapTempt = 0;
  10. u8 gap_min = 0; //【当前间歇时间】分钟
  11. u8 gap_s = 0; //【当前间歇时间】秒
  12. u8 gapNum = 16; //【时停按键矩阵】返回值——修改时间
  13. u8 recard_rudderNum = 0; // 记录上一次的值
  14. u8 recard_gap_min = 0;
  15. u8 recard_gap_s = 0;
  16. int rotateCount = 0; //【旋转按键】的按下次数
  17. u8 parameter1 = 0; //【数码管显示】参数1
  18. u8 parameter2 = 0; //【数码管显示】参数2
  19. u8 mode_digitalTube = 0; //【数码管显示】模式
  20. u8 flickerNum = 2; //【数码管显示】逻辑切换的闪烁次数
  21. u8 controlNum = 0; //敲定【确认键】or【选择键】
  22. u8 tempRudderNum = 0;
  23. u8 angle = 0;
  24. u8 angleSign = 0;
  25. Init();
  26. while(1)
  27. {
  28. // 选择舵机
  29. tempRudderNum = SelectKEY_Scan(TIMES);
  30. if(tempRudderNum != 0)
  31. rudderNum = tempRudderNum;
  32. // 时停按键矩阵
  33. if(rudderNum <= 8 && rudderNum >= 1 && mode_digitalTube == 0)
  34. gapNum = TimeGapKEY_Scan(TIMES);
  35. if(gapNum <= 15 && gapNum >= 0)
  36. {
  37. gapTempt = gapTime + CountTime(gapNum);
  38. if( gapTempt >= 0 && gapTempt <= 1800) // 单次[0, 30]min以内
  39. gapTime += CountTime(gapNum);
  40. // 计算时间
  41. gap_min = gapTime/60;
  42. gap_s = gapTime%60;
  43. // 优先显示分钟逻辑
  44. if(gap_min >= 10)
  45. gap_s /= 10;
  46. }//if
  47. // 旋转角度
  48. if(RotateKEY_Scan(TIMES) == 1 && mode_digitalTube == 1)
  49. {
  50. rotateCount++;
  51. // 计算(参数1-正负)(参数2-十位的数值)的逻辑
  52. if(rotateCount/7 != 0)
  53. {
  54. rotateCount = -6;
  55. }
  56. if(rotateCount < 0)
  57. {
  58. angleSign = 1;
  59. angle = -1*rotateCount;
  60. }
  61. else
  62. {
  63. angleSign = 0;
  64. angle = rotateCount;
  65. }
  66. }//if
  67. // 确认键 <-> 1 和 复位键 <-> 2
  68. controlNum = ControlKEY_Scan(TIMES);
  69. if(controlNum != 0)
  70. {
  71. if(mode_digitalTube == 1)
  72. {
  73. mode_digitalTube = 0;
  74. }
  75. else
  76. {
  77. mode_digitalTube = 1;
  78. parameter1 = angleSign;
  79. parameter2 = angle;
  80. }
  81. switch(controlNum)
  82. {
  83. case 1:
  84. {
  85. //实现数据保存
  86. Save_InputData(rudderNum, gapTime,angle, angleSign);
  87. }break;
  88. case 2:
  89. {
  90. //实现数据恢复默认
  91. Reset_InputData(rudderNum);
  92. }break;
  93. }//switch
  94. }//if
  95. if(mode_digitalTube == 0)
  96. {
  97. parameter1 = gap_min;
  98. parameter2 = gap_s;
  99. }
  100. if(mode_digitalTube == 1)
  101. {
  102. parameter1 = angleSign;
  103. parameter2 = angle;
  104. }
  105. Display_DigitalTube(rudderNum, parameter1, parameter2, mode_digitalTube);
  106. }//while
  107. }

function.c

  1. #include <reg52.h>
  2. #include <function.h>
  3. u8 messageIndex = 0; //【保存数据】s数组的索引
  4. u8 MESSAGE[];
  5. void Init()
  6. {
  7. P2 = 0x00;
  8. P3 &= 0x0f;
  9. KEY_RO = 0;
  10. KEY_OK = 0;
  11. }
  12. u8 code KEY_TABLE[] =
  13. {
  14. 0xEE, 0xDE, 0xBE, 0x7E,
  15. 0xED, 0xDD, 0xBD, 0x7D,
  16. 0xEB, 0xDB, 0xBB, 0x7B,
  17. 0xE7, 0xD7, 0xB7, 0x77
  18. };
  19. u8 code LedChar[10]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
  20. u8 code LedBuff[4]={0xFF, 0xFF, 0xFF, 0xFF};//初始化数码管显示缓存区
  21. // 输入数据的声明
  22. struct servoMotorData inputData[8];
  23. void Delay_ms(u16 x)
  24. {
  25. u16 i,j;
  26. if(x==1000)
  27. {
  28. for(i=0;i<19601;i++)//延时1s
  29. {
  30. for(j=5;j>0;j--);
  31. }
  32. }
  33. else while(x--)for(j=115;j>0;j--);
  34. }
  35. // 扫描选择舵机的按键 返回舵机编号
  36. u8 SelectKEY_Scan(u8 TIMES)
  37. {
  38. static u8 key_up = 1;
  39. if(key_up == 1 && (KEY_S0 == 1||KEY_S1 == 1||KEY_S2 == 1||KEY_S3 == 1||KEY_S4 == 1
  40. ||KEY_S5 == 1 ||KEY_S6== 1||KEY_S7 == 1))
  41. {
  42. Delay_ms(TIMES);
  43. if(KEY_S0 == 1) return 1;
  44. else if(KEY_S1 == 1) return 2;
  45. else if(KEY_S2 == 1) return 3;
  46. else if(KEY_S3 == 1) return 4;
  47. else if(KEY_S4 == 1) return 5;
  48. else if(KEY_S5 == 1) return 6;
  49. else if(KEY_S6 == 1) return 7;
  50. else if(KEY_S7 == 1) return 8;
  51. }
  52. else if(KEY_S0 == 0&&KEY_S1 == 0 &&KEY_S2 == 0&& KEY_S3 == 0 &&KEY_S4 == 0&&
  53. KEY_S5 == 0&& KEY_S6== 0&& KEY_S7 == 0) //检测到松开
  54. key_up = 1;
  55. return 0; //无按键按下;
  56. }
  57. // 时停按键矩阵 返回按键编号
  58. u8 TimeGapKEY_Scan(u8 TIMES)
  59. {
  60. u8 temp, key, key_num;
  61. static u8 key_up = 1;
  62. P1 = 0Xf0; // 行低列高
  63. // 若高四位不全为1,说明有按键按下
  64. if((P1&0xf0) != 0Xf0 && key_up == 1)
  65. {
  66. Delay_ms(TIMES); // 消抖
  67. key_up = 0;
  68. if((P1&0xf0) != 0Xf0)
  69. {
  70. temp = P1;
  71. // 列检测
  72. P1 = 0x0f;
  73. key = temp|P1;
  74. for(key_num = 0; key_num < 16; key_num++)
  75. if(key == KEY_TABLE[key_num])
  76. break;
  77. return key_num;
  78. }//if
  79. }//if
  80. else if((P1&0xf0) == 0Xf0)
  81. key_up = 1;
  82. return 16; //无键按下,返回16
  83. }
  84. // 根据按键编号间隔计算时间
  85. int CountTime(u8 gapNum)
  86. {
  87. int addTime = 0;
  88. // 加权
  89. switch(gapNum/4)
  90. {
  91. case 0: addTime = 60; break;
  92. case 1: addTime = -60; break;
  93. case 2: addTime = 1; break;
  94. case 3: addTime = -1; break;
  95. }
  96. // 赋值
  97. switch(gapNum%4)
  98. {
  99. case 0: addTime *= 20; break;
  100. case 1: addTime *= 10; break;
  101. case 2: addTime *= 5; break;
  102. case 3: addTime *= 1; break;
  103. }
  104. return addTime;
  105. }
  106. // 数码管显示 mode:(0-间隔时间模式)(1-旋转角度模式)
  107. void Display_DigitalTube(u8 rudderNum, u8 parameter1, u8 parameter2, u8 mode_digitalTube)
  108. {
  109. // 先做舵机选择位的显示,再做其他
  110. P3 &= 0x0f; // 先将高四位置0,在修改高四位的值
  111. P3 |= 0x10;
  112. P0 = LedChar[rudderNum];
  113. Delay_ms(1);
  114. // 间隔时间模式
  115. if(mode_digitalTube == 0)
  116. {
  117. if(parameter1 < 10 && parameter2 < 10) //a 1.01
  118. {
  119. P3 &= 0x0f;
  120. P3 |= 0x20;
  121. P0 = LedChar[parameter1]&0x7f; //&0x7f —— 点亮小数点
  122. Delay_ms(1);
  123. P3 &= 0x0f;
  124. P3 |= 0x40;
  125. P0 = LedChar[0];
  126. Delay_ms(1);
  127. }
  128. else if(parameter1 < 10 && parameter2 >= 10) //a1.11
  129. {
  130. P3 &= 0x0f;
  131. P3 |= 0x20;
  132. P0 = LedChar[parameter1]&0x7f;
  133. Delay_ms(1);
  134. P3 &= 0x0f;
  135. P3 |= 0x40;
  136. P0 = LedChar[parameter2/10];
  137. Delay_ms(1);
  138. }
  139. else //a11.1
  140. {
  141. P3 &= 0x0f;
  142. P3 |= 0x20;
  143. P0 = LedChar[parameter1/10];
  144. Delay_ms(1);
  145. P3 &= 0x0f;
  146. P3 |= 0x40 ;
  147. P0 = LedChar[parameter1%10]&0x7f;
  148. Delay_ms(1);
  149. }
  150. // 秒钟的个位代码相同
  151. P3 &= 0x0f;
  152. P3 |= 0x80;
  153. P0 = LedChar[parameter2%10];
  154. Delay_ms(1);
  155. }
  156. // 旋转角度模式
  157. else
  158. {
  159. // 正:舵机号 角度 负:舵机号-角度
  160. P3 &= 0x0f;
  161. P3 |= 0x20;
  162. if(parameter1 == 1)
  163. P0 = 0xbf; //显示负号
  164. if(parameter1 == 0)
  165. P0 = 0xff;
  166. Delay_ms(1);
  167. P3 &= 0x0f; // 显示角度
  168. P3 |= 0x40;
  169. P0 = LedChar[parameter2];
  170. Delay_ms(1);
  171. P3 &= 0x0f; // 显示0
  172. P3 |= 0x80;
  173. P0 = LedChar[0];
  174. Delay_ms(1);
  175. }
  176. }
  177. // 旋转按键
  178. u8 RotateKEY_Scan(u8 TIMES)
  179. {
  180. static u8 key_up = 1;
  181. if(KEY_RO == 1 && key_up == 1)
  182. {
  183. Delay_ms(TIMES);
  184. key_up = 0;
  185. if(KEY_RO == 1)
  186. return 1;
  187. }
  188. else if(KEY_RO == 0)
  189. key_up = 1;
  190. return 0; //无按键按下;
  191. }
  192. // 数码管闪烁反馈
  193. void Flicker_DigitalTube(u8 rudderNum, u8 parameter1, u8 parameter2, u8 mode_digitalTube, u8 flickerNum)
  194. {
  195. for(; flickerNum > 0; flickerNum--)
  196. {
  197. Display_DigitalTube(rudderNum, parameter1, parameter2, mode_digitalTube);
  198. // 四个依次灭掉
  199. P3 &= 0x0f;
  200. P3 |= 0x80;
  201. P0 = 0xff;
  202. Delay_ms(1);
  203. P3 &= 0x0f;
  204. P3 |= 0x40;
  205. P0 = 0xff;
  206. Delay_ms(1);
  207. P3 &= 0x0f;
  208. P3 |= 0x20;
  209. P0 = 0xff;
  210. Delay_ms(1);
  211. P3 &= 0x0f;
  212. P3 |= 0x10;
  213. P0 = 0xff;
  214. Delay_ms(1);
  215. }
  216. }
  217. // 确认键和复位键的扫描
  218. u8 ControlKEY_Scan(u8 TIMES)
  219. {
  220. static u16 times;
  221. static key_up = 1;
  222. if((KEY_RE == 1 || KEY_OK == 1) && key_up == 1)
  223. {
  224. times++; //记录进入高电平的时间
  225. if(times >= TIMES) //抖动时间已经过去
  226. {
  227. times = 0;
  228. if(KEY_OK == 1) return 1;
  229. else if(KEY_RE == 1) return 0;
  230. }
  231. }
  232. return 0; //无按键按下;
  233. }
  234. // 输入数据的保存——核心是依次修改该舵机下的角度和间隔时间
  235. void Save_InputData(u8 rudderNum, u16 gapTime, u8 rotateCount, u8 rotateSign)
  236. {
  237. u8 num;
  238. if(rudderNum < 0 || rudderNum >8) return;
  239. num = rudderNum - 1;
  240. // 角度和间隔时间的赋值
  241. if(inputData[num].gapIndex >= 0 && inputData[num].gapIndex < 4)
  242. inputData[num].gapTime[inputData[num].gapIndex++] = gapTime;
  243. if(inputData[num].rotateIndex >= 0 && inputData[num].rotateIndex < 3)
  244. {
  245. // 此处旋转角度不做乘10处理,再另一个单片机上确定真实数据
  246. inputData[num].rotateAngle[inputData[num].rotateIndex++] = rotateCount;
  247. if(rotateSign == 1)
  248. inputData[num].rotateAngle[inputData[num].rotateIndex] *= -1;
  249. }
  250. }
  251. // 数据复位——核心是一一重置该舵机下的角度和间隔时间
  252. void Reset_InputData(u8 rudderNum)
  253. {
  254. u8 num, i;
  255. if(rudderNum < 0 || rudderNum >8) return;
  256. num = rudderNum - 1;
  257. // 角度和间隔时间的复位
  258. for(i = 0; i < inputData[num].gapIndex; i++)
  259. inputData[num].gapTime[i] = 0;
  260. for(i = 0; i < inputData[num].rotateIndex; i++)
  261. inputData[num].rotateAngle[i] = 0;
  262. inputData[num].gapIndex = 0;
  263. inputData[num].rotateIndex = 0;
  264. }
  265. void SendData()
  266. {
  267. // 数据写入数组
  268. u16 writeIndex = 0;
  269. u8 structIndex = 0;
  270. u8 temp_gapIndex = 0;
  271. u8 temp_rotateIndex = 0;
  272. u8 servoMotorNum = 'A' - 1; //表示1号舵机
  273. u8 i = 0;
  274. /* 写入数据格式
  275. A rotateIndex gapTime[] rotateAngle[]
  276. B……
  277. */
  278. for(; structIndex < 8; structIndex++)
  279. {
  280. // 写入舵机号(A~H)
  281. servoMotorNum++;
  282. MESSAGE[writeIndex++] = servoMotorNum;
  283. // 如果此舵机没有数据可写,跳过
  284. temp_rotateIndex = inputData[structIndex].rotateIndex;
  285. if(temp_rotateIndex == 0)
  286. {
  287. structIndex++;
  288. continue;
  289. }
  290. else
  291. {
  292. /*
  293. 此舵机无需旋转时,仅保存舵机字母
  294. 若需旋转,第二位表示选择角度个数
  295. timeNum = rotateNum + 1;
  296. */
  297. MESSAGE[writeIndex++] = temp_rotateIndex;
  298. }
  299. // 写入时间
  300. temp_gapIndex = inputData[structIndex].gapIndex;
  301. for(; temp_gapIndex > 0; temp_gapIndex--)
  302. {
  303. i = 0;
  304. MESSAGE[writeIndex++] = inputData[structIndex].gapTime[i];
  305. i++;
  306. }
  307. // 写入角度
  308. temp_rotateIndex = inputData[structIndex].rotateIndex;
  309. for(; temp_rotateIndex > 0; temp_rotateIndex--)
  310. {
  311. i = 0;
  312. MESSAGE[writeIndex++] = inputData[structIndex].rotateAngle[i];
  313. i++;
  314. }
  315. }
  316. // 串口初始化
  317. SCON = 0x50;//设置串行口工作方式1,接收控制打开
  318. TMOD |= 0x20;//定时器1设置工作方式2
  319. TH1 = 0xFD;//设置波特率为9600,数据位8,停止位1,无校验位,晶振频率11.0592M
  320. TL1 = 0xFD;
  321. TR1 = 1;//启动定时器1
  322. // 发送数据
  323. messageIndex = 0;
  324. while(MESSAGE[messageIndex] != '\0')
  325. {
  326. SBUF = MESSAGE[messageIndex];//将一个字符放入串行数据缓冲器SBUF
  327. while(!TI);//等待发送中断标志为1
  328. TI = 0;//清除发送中断标志
  329. messageIndex++;//准备下一个字符
  330. }
  331. Delay_ms(500);//延时
  332. }

function.h

  1. #ifndef __FUNCTION_H__
  2. #define __FUNCTION_H__
  3. typedef unsigned char u8;//对数据类型进行声明定义
  4. typedef unsigned int u16;
  5. typedef unsigned long u32;
  6. // 数码管段选-直接对P0口操作
  7. // 时停按键矩阵-直接对P1口操作
  8. // 定义与选择舵机按键连接的位
  9. sbit KEY_S0 = P2^0;
  10. sbit KEY_S1 = P2^1;
  11. sbit KEY_S2 = P2^2;
  12. sbit KEY_S3 = P2^3;
  13. sbit KEY_S4 = P2^4;
  14. sbit KEY_S5 = P2^5;
  15. sbit KEY_S6 = P2^6;
  16. sbit KEY_S7 = P2^7;
  17. // 数码管位选+其他按键+数据传输
  18. sbit KEY_RO = P3^2;
  19. sbit KEY_OK = P3^3;
  20. sbit KEY_RE = P3^0;
  21. sbit DigitalTube_w = P3^4;
  22. sbit DigitalTube_x = P3^5;
  23. sbit DigitalTube_y = P3^6;
  24. sbit DigitalTube_z = P3^7;
  25. extern u8 MESSAGE[];
  26. //数码管状态值初始化
  27. extern u8 code LedChar[10];
  28. extern u8 code LedBuff[4];
  29. //舵机结构体
  30. extern struct servoMotorData inputData[8];
  31. struct servoMotorData
  32. {
  33. u16 gapTime[4];
  34. u8 gapIndex; // 记录舵机间歇时间数组的索引
  35. char rotateAngle[3];
  36. u8 rotateIndex; // 记录舵机旋转角度数组的索引
  37. };
  38. // 声明在 function.c 中定义的函数
  39. void Init();
  40. void Delay_ms(u16);
  41. u8 SelectKEY_Scan(u8);
  42. u8 TimeGapKEY_Scan(u8);
  43. int CountTime(u8);
  44. void Display_DigitalTube(u8, u8, u8, u8);
  45. u8 RotateKEY_Scan(u8);
  46. void Flicker_DigitalTube(u8, u8, u8, u8, u8);
  47. u8 ControlKEY_Scan(u8);
  48. void Save_InputData(u8, u16, u8, u8);
  49. void Reset_InputData(u8);
  50. void SendData();
  51. #endif