[讨论] 纯属好玩,基于STC51的4位数码管驱动模块

karajanlee   2014-1-17 15:55 楼主
如题,真的是纯属好玩,用串口接收数据,单独的MCU来显示数据,所以不会闪烁,可以减轻主MCU的运算压力。。哈哈。。 电路图 IMG_20140117_141005.jpg 洞洞板效果,数码管叠在MCU上。。。 shots.jpg
  1. /**
  2. * 基于STC15W204S的串口4位LED驱动模块
  3. *
  4. * 串口波特率: 9600 bps
  5. * 单次发送数据长度: 8 位
  6. * 格式:
  7. * 字符索引1 控制位1 ... 字符索引4 控制位4
  8. * 字符索引列表:
  9. * 00 -> 0, 01 -> 1, 02 -> 2, 03 -> 3, 04 -> 4,
  10. * 05 -> 5, 06 -> 6, 07 -> 7, 08 -> 8, 09 -> 9,
  11. * 0A -> -, 0B -> A, 0C -> b, 0D -> c, 0E -> d,
  12. * 0F -> E, 10 -> F, 11 -> g, 12 -> H, 13 -> J,
  13. * 14 -> L, 15 -> n, 16 -> o, 17 -> p, 18 -> q,
  14. * 19 -> r, 1A -> S, 1B -> t, 1C -> U, 1D -> y,
  15. * 控制位:
  16. * -----------------------------------------------------------
  17. * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
  18. * |---------------------------------------------------------|
  19. * | x | x | x | x | x | x | 0/1 | 0/1 |
  20. * |---------------------------------------------------------|
  21. * | 0:| 不显示小数点 | 不显示当前位字符 |
  22. * | 1:| 显示小数点 | 显示当前位字符 |
  23. * -----------------------------------------------------------
  24. *
  25. * No license applied. Use as you wish.
  26. * Happy Coding!
  27. *
  28. * 2014 (c) K% Design
  29. * by HouYu Li <lihouyu@phpex.net>
  30. */
  31. #include <INTRINS.H>
  32. #include <STC/STC15F2K60S2.H>
  33. sbit CommD1 = P1 ^ 1; // 数字1(最高位)共阴极 P1.1
  34. sbit CommD2 = P3 ^ 6; // 数字2共阴极 P3.6
  35. sbit CommD3 = P3 ^ 3; // 数字3共阴极 P3.3
  36. sbit CommD4 = P5 ^ 5; // 数字4共阴极 P5.5
  37. unsigned char MaskCommD1 = 0x02; // 数字1共阴极Byte表示形式
  38. unsigned char MaskCommD2D3 = 0x48; // 数字2,3共阴极合并Byte表示形式
  39. unsigned char MaskCommD4 = 0x20; // 数字4共阴极Byte表示形式
  40. unsigned char UARTPINEN = 0x03; // 置高P3.0, P3.1使串口工作正常
  41. /**
  42. * 以下是各个字符的段码,由于没有足够的IO,并简化了硬件连接
  43. * 所以导致需要三组端口配合来实现字符显示
  44. */
  45. unsigned char P1SEG[30] = {0x2D, 0x20, 0x0D, 0x29, 0x20,
  46. 0x29, 0x2D, 0x21, 0x2D, 0x29,
  47. 0x00, 0x25, 0x2C, 0x0C, 0x2C,
  48. 0x0D, 0x05, 0x29, 0x24, 0x28,
  49. 0x0C, 0x24, 0x2C, 0x05, 0x21,
  50. 0x04, 0x29, 0x0C, 0x2C, 0x28};
  51. /* 为了节约内存,改用switch选择语句
  52. unsigned char P3SEG[30] = {0x84, 0x04, 0x04, 0x04, 0x84,
  53. 0x80, 0x80, 0x04, 0x84, 0x84,
  54. 0x00, 0x84, 0x80, 0x00, 0x04,
  55. 0x80, 0x80, 0x84, 0x84, 0x04,
  56. 0x80, 0x00, 0x00, 0x84, 0x84,
  57. 0x00, 0x80, 0x80, 0x84, 0x84};
  58. unsigned char P5SEG[30] = {0x00, 0x00, 0x10, 0x10, 0x10,
  59. 0x10, 0x10, 0x00, 0x10, 0x10,
  60. 0x10, 0x10, 0x10, 0x10, 0x10,
  61. 0x10, 0x10, 0x10, 0x10, 0x00,
  62. 0x00, 0x10, 0x10, 0x10, 0x10,
  63. 0x10, 0x10, 0x10, 0x00, 0x10};
  64. */
  65. /** // */
  66. // 串口接收数据缓存
  67. unsigned char UARTBUFF[8] = {0, 0x01, 0, 0x03, 0, 0x01, 0, 0x01};
  68. // 串口接收自己位置索引
  69. unsigned char idxUARTBUFF = 0;
  70. // 存放显示数据
  71. unsigned char DISPBUFF[8] = {1, 0x01, 2, 0x03, 3, 0x01, 4, 0x01};
  72. // 接收数据长度
  73. unsigned char BUFFLEN = 8;
  74. // 数据是否接受完毕
  75. char RXDONE = 0;
  76. //char TXBUSY = 0;
  77. void initIO();
  78. void showChar(unsigned char idx, unsigned char segidx, unsigned char ctrl);
  79. /**
  80. * 以下代码由STC刷机工具生成
  81. */
  82. void Delay1ms();
  83. void initUart(void);
  84. void Delay1ms() //@11.0592MHz
  85. {
  86. unsigned char i, j;
  87. _nop_();
  88. _nop_();
  89. _nop_();
  90. i = 11;
  91. j = 190;
  92. do
  93. {
  94. while (--j);
  95. } while (--i);
  96. }
  97. void initUart(void) //9600bps@11.0592MHz
  98. {
  99. SCON = 0x50; //8位数据,可变波特率
  100. AUXR |= 0x04; //定时器2时钟为Fosc,即1T
  101. T2L = 0xE0; //设定定时初值
  102. T2H = 0xFE; //设定定时初值
  103. AUXR |= 0x01; //串口1选择定时器2为波特率发生器
  104. AUXR |= 0x10; //启动定时器2
  105. // 以下2行代码自行添加
  106. EA = 1; //启用系统总中断和串口中断
  107. ES = 1;
  108. }
  109. /** // */
  110. /**
  111. * 初始化IO
  112. */
  113. void initIO() {
  114. // 将所有驱动LED的IO设置成强推挽模式
  115. // 除了P3.0, P3.1
  116. P1M0 = 0x3D + MaskCommD1;
  117. P3M0 = 0x84 + MaskCommD2D3;
  118. P5M0 = 0x10 + MaskCommD4;
  119. // 将IO赋初始值
  120. // 共阴极IO置高
  121. // 字符段IO置低
  122. // 保持P3.0, P3.1为高
  123. P1 = MaskCommD1;
  124. P3 = MaskCommD2D3 + UARTPINEN;
  125. P5 = MaskCommD4;
  126. }
  127. /**
  128. * 显示字符
  129. * 参数:idx 显示第几个字符,从左到右顺序为1,2,3,4
  130. * 参数:segidx 要显示的字符索引值
  131. * 参数:ctrl 当前字符的控制位
  132. */
  133. void showChar(unsigned char idx, unsigned char segidx, unsigned char ctrl) {
  134. if (ctrl & 1 && idx < 30) { // 确认当前字符的索引值有效
  135. // 要同时设置好P1, P3和P5才能正常显示字符
  136. // 设置Port1
  137. P1 = P1SEG[segidx] + MaskCommD1;
  138. // 设置Port3
  139. //P3 = P3SEG[segidx] + MaskCommD2D3 + UARTPINEN;
  140. switch (segidx) {
  141. case 1:
  142. case 2:
  143. case 3:
  144. case 7:
  145. case 14:
  146. case 19:
  147. P3 = 0x04 + MaskCommD2D3 + UARTPINEN;
  148. break;
  149. case 10:
  150. case 13:
  151. case 21:
  152. case 22:
  153. case 25:
  154. P3 = MaskCommD2D3 + UARTPINEN;
  155. break;
  156. case 5:
  157. case 6:
  158. case 12:
  159. case 15:
  160. case 16:
  161. case 20:
  162. case 26:
  163. case 27:
  164. P3 = 0x80 + MaskCommD2D3 + UARTPINEN;
  165. break;
  166. default:
  167. P3 = 0x84 + MaskCommD2D3 + UARTPINEN;
  168. break;
  169. }
  170. // 设置Port5
  171. //P5 = P5SEG[segidx] + MaskCommD4;
  172. switch (segidx) {
  173. case 0:
  174. case 1:
  175. case 7:
  176. case 9:
  177. case 20:
  178. case 28:
  179. P5 = MaskCommD4;
  180. break;
  181. default:
  182. P5 = 0x10 + MaskCommD4;
  183. break;
  184. }
  185. // 是否显示小数点
  186. if (ctrl & 2)
  187. P1 |= 0x10;
  188. // 置低相应位的共阴极IO
  189. switch (idx) {
  190. case 1:
  191. CommD1 = 0;
  192. break;
  193. case 2:
  194. CommD2 = 0;
  195. break;
  196. case 3:
  197. CommD3 = 0;
  198. break;
  199. case 4:
  200. CommD4 = 0;
  201. break;
  202. }
  203. }
  204. }
  205. /**
  206. * 主函数
  207. */
  208. void main() {
  209. initIO(); // 初始化IO
  210. initUart(); // 初始化串口
  211. while (1) {
  212. if (RXDONE == 1) {
  213. /**
  214. while (TXBUSY);
  215. TXBUSY = 1;
  216. SBUF = DISPBUFF[4];
  217. */
  218. RXDONE = 0;
  219. // 当接收完数据后重置IO,准备显示新的数字
  220. P1 = MaskCommD1;
  221. P3 = MaskCommD2D3 + UARTPINEN;
  222. P5 = MaskCommD4;
  223. }
  224. showChar(1, DISPBUFF[0], DISPBUFF[1]);
  225. Delay1ms();
  226. showChar(2, DISPBUFF[2], DISPBUFF[3]);
  227. Delay1ms();
  228. showChar(3, DISPBUFF[4], DISPBUFF[5]);
  229. Delay1ms();
  230. showChar(4, DISPBUFF[6], DISPBUFF[7]);
  231. Delay1ms();
  232. }
  233. }
  234. /**
  235. * 串口中断
  236. */
  237. void UART() interrupt 4 using 1 {
  238. if (RI) {
  239. RI = 0;
  240. UARTBUFF[idxUARTBUFF] = SBUF;
  241. idxUARTBUFF++;
  242. // 当接收完指定长度(BUFFLEN)的数据之后
  243. // 把串口接收数据缓存的数据复制到显示的缓存中
  244. // 同时重置了串口接收缓存位置索引
  245. if (idxUARTBUFF == BUFFLEN) {
  246. while (idxUARTBUFF > 0) {
  247. idxUARTBUFF--;
  248. DISPBUFF[idxUARTBUFF] = UARTBUFF[idxUARTBUFF];
  249. }
  250. RXDONE = 1;
  251. }
  252. }
  253. /**
  254. if (TI) {
  255. TI = 0;
  256. TXBUSY = 0;
  257. }
  258. */
  259. }
本帖最后由 karajanlee 于 2014-1-17 16:05 编辑

回复评论 (7)

把代码和二进制文件附加一下 本帖最后由 karajanlee 于 2014-1-17 16:06 编辑

    main.c.zip (2014-1-17 15:59 上传)

    2.54 KB, 下载次数: 13

    代码

    Digits.hex.zip (2014-1-17 15:59 上传)

    1008 Bytes, 下载次数: 11

    二进制文件

点赞  2014-1-17 15:59
现在的51机的价格很低了,用这种办法完成显示倒是值得推广的。
点赞  2014-1-17 22:03
修复数字9的显示错误..

    Digits.zip (2014-1-28 15:58 上传)

    1021 Bytes, 下载次数: 17

    main.zip (2014-1-28 15:58 上传)

    2.59 KB, 下载次数: 25

点赞  2014-1-28 15:58
不错,程序可以更好些,加上ADC功能可以做表头了
点赞  2014-1-29 02:04
呵呵,升级版了。。
做了一片PCB,原始设计用的是0.36英寸的数码管,共阴极只是加了限流电阻,这次升级共阴极加了三极管,设计的时候是想把PCB做成数码管一样大小的,于是0.36的面积有点紧张,于是换成了0.56英寸的数码管了。接口方面仍然是支持FTDI的USB转RS232的工具的,外加了利用FTDI工具上的DTR端口进行单片机自动硬重启的功能,刷程序就简单多了。。呵呵。。。程序有改动,晚上回去传,先上图片和电路图,还有PCB的生产文件,有兴趣的同学可以玩玩。。

正面+PCB

侧面

背面

电路图

点赞  2014-3-11 11:29
你好,请问VCC电源电压是 几V的?
点赞  2018-5-23 10:48
3.3V可以直接驱动三极管来 驱动控制 数码管亮吗
点赞  2018-5-23 10:50
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复