0


使用单片机的IO引脚直接驱动段码屏

使用单片机的IO引脚直接驱动段码屏,目的是为了降低成本。这种古老的应用,在低功耗产品中比较多见。
如:水表,燃气表等需要电池供电的产品。

下面纯属个人理解,未经测试。

1/3Duty表示LCD共有3个COM引脚,分别占显示周期的1/3
1/2BIAS表示电压0和VCC

1、LCD的COM引脚电压
由于是1/2bias的LCD,因此需在COM引脚产生三种电压:0V、0.5VDD、VDD。实现方法如下:
1)、将LCD的COM引脚通过10K电阻分别连接至VDD和GND;
2)、当CPU连接到COM引脚的IO口配置为输入浮空时,则COM引脚会产生0.5倍VDD的电压;
3)、当CPU连接到COM引脚的IO口输出低电平时,则COM引脚会产生GND电压;
4)、当CPU连接到COM引脚的IO口输出高电平时,则COM引脚会产生VDD电压;
因此,在使用CPU的IO口直接驱动1/2bias的LCD时,要求CPU的IO引脚具有三态输出功能;

2、显示方法:

1)、显示时,交替翻转COM引脚和SEG引脚电压
COM引脚电压为VCC,SEG引脚电压为0,交替后,则为COM引脚电压为0,SEG引脚电压为VCC;
2)、不显示时,交替翻转COM引脚和SEG引脚电压
COM引脚电压为VCC,SEG引脚电压为VCC,交替后,则为COM引脚电压为0,SEG引脚电压为0;

只要COM引脚和SEG引脚的电压差为+VCC或者-VCC,就可以点亮对应的LCD笔段即像素点,具体实现步骤如下:
第1次中断时设置COM0引脚输出High,其它COM引脚输出VDD/2,再根据要显示的数据设置各个SEG的输出;
第2次中断时设置COM0引脚输出Low,其它COM引脚输出VDD/2,再根据要显示的数据设置各个SEG的输出;
第3次中断时设置COM1引脚输出High,其它COM引脚输出VDD/2,再根据要显示的数据设置各个SEG的输出;
第4次中断时设置COM1引脚输出Low,其它COM引脚输出VDD/2,再根据要显示的数据设置各个SEG的输出;
第5次中断时设置COM2引脚输出High,其它COM引脚输出VDD/2,再根据要显示的数据设置各个SEG的输出;
第6次中断时设置COM2引脚输出Low,其它COM引脚输出VDD/2,再根据要显示的数据设置各个SEG的输出;
循环进行以上的6次循环设置,即可完成“使用单片机IO模拟驱动段码LCD”;

3、占空比和偏压比的关系:

一般来说,Bias的选择与COM使用个数有关,但不是绝对。见下图:

4、选择单片机直接驱动LCD,还是选择专用的驱动芯片,以及注意事项如下:
1)、单片机本身不带LCD驱动功能,在使用单片机IO直接驱动段码LCD时,偏压比只能选择1/2。
在LCD的COM引脚加上拉、下拉各1个电阻,阻值一般为100-200K;选择偏压比为1/3,也可以用,但效果没有1/2好。

2)、MCU+专用的LCD显示驱动芯片:
常用的驱动芯片有1621、1622,对应的偏压比为1/3、1/4,LCD的COM引脚就不需要外加电阻了,而且单片机可以选择相对脚位少的、资源少点的,这样单片机的价格会便宜,但驱动芯片不便宜;

若供电电压小于4.5V,建议选择1/2偏压。使用1/2偏压,液晶抖度相对大一些,在垂直视角看的会比较清楚,并且可以过12点法线
如果供电电压小于4.5V,选择1/3偏压,虽然也可以用,但是没有1/2偏压的显示效果好,且过不了12点垂直法线。

5、其它信息
一般LCD液晶屏有三个主要参数,工作中电压Duty(相匹配COM数)和BIAS(偏压,相匹配阀值)。
例如,3.3V、1/4 Duty、1/3 BIAS表明LCD的工作中电压为3.3V,有4个COM,阀值大概是1.1V(3.3/3=1.1)。
具体应用中,为确保显示实际效果优良,一般给电极两边加的电压差贴近LCD的工作中电压;若想不显示,一般
给电极两边加的电压差贴近0V。
必须需注意的是,lcd屏分子结构是必须通过交流数据信号来推动的,千万不能将直流电电压长期的加进电极两边,不然,会危害lcd屏分子结构的电化学特点,造成显示实际效果模糊不清,使用期限降低的不良影响,不可修复。
1/4 Duty、1/3 BIAS的LCD点亮方法如下:
点亮某一段时,必须确保给其电极两边加的电压差为3.3V,如COM1=3.3V,SEG1=0V,而且保持合适的时
间间距,然后再将COM1和SEG1引脚的电压翻转輸出,如COM1=0V,SEG1=3.3V;
不点亮某一段时,必须确保给其电极两边加的电压差为0V,如COM1=3.3V,SEG1=3.3V,,而且保持合适的时
间间距,然后再将COM1和SEG1引脚的电压翻转輸出,如COM1=0V,SEG1=0V;

6、SegmentCodeScreen.c测试程序

以下程序未经测试,只是理论,没有板子测试。

  1. #include "SegmentCodeScreen.h"
  2. /*
  3. 使用单片机的IO引脚直接驱动段码屏,目的是为了降低成本。这种古老的应用,在低功耗产品中比较多见。
  4. 如:水表,燃气表等需要电池供电的产品。
  5. 1/3Duty表示LCD共有3个COM引脚,分别占显示周期的1/3
  6. 1/2BIAS表示电压0和VCC
  7. LCD的COM引脚电压
  8. 由于是1/2bias的LCD,因此需在COM引脚产生三种电压:0V、0.5VDD、VDD。实现方法如下:
  9. 1)、将LCD的COM引脚通过10K电阻分别连接至VDD和GND;
  10. 2)、当CPU连接到COM引脚的IO口配置为输入浮空时,则COM引脚会产生0.5倍VDD的电压;
  11. 3)、当CPU连接到COM引脚的IO口输出低电平时,则COM引脚会产生GND电压;
  12. 4)、当CPU连接到COM引脚的IO口输出高电平时,则COM引脚会产生VDD电压;
  13. 因此,在使用CPU的IO口直接驱动1/2bias的LCD时,要求CPU的IO引脚具有三态输出功能;
  14. 由于是1/3duty的LCD,所以COM引脚的波形图如下:
  15. COM0电压波形图:
  16. 3V __ __
  17. | | | |
  18. 1.5V __| | __________| | ___________
  19. | | | |
  20. 0V |__| |__|
  21. COM1电压波形图:
  22. 3V __ __
  23. | | | |
  24. 1.5V ________| | __________| | _____
  25. | | | |
  26. 0V |__| |__|
  27. COM2电压波形图:
  28. 3V __ __
  29. | | | |
  30. 1.5V ______________| | __________| |
  31. | | | |
  32. 0V |__| |__|
  33. 如果SEG1电压波形图如下,根据上面的COM0,COM1和COM2引脚波形,则SEG1和COM交点处的笔画码不会显示:
  34. 3V __ __ __ __ __ __
  35. | | | | | | | | | | | |
  36. 1.5V __| | | | | | | | | | | |
  37. | | | | | | | | | | | |
  38. 0V |__| |__| |__| |__| |__| |__|
  39. 如果SEG1电压波形图如下,根据上面的COM0,COM1和COM2引脚波形,则SEG1和COM交点处的笔画码会显示:
  40. 3V __ __ __ __ __ __
  41. | | | | | | | | | | | |
  42. 1.5V __ | | | | | | | | | | | |
  43. | | | | | | | | | | | |
  44. 0V |__| |__| |__| |__| |__| |__|
  45. 1)、显示时,交替翻转COM引脚和SEG引脚电压
  46. COM引脚电压为VCC,SEG引脚电压为0,交替后,则为COM引脚电压为0,SEG引脚电压为VCC;
  47. 2)、不显示时,交替翻转COM引脚和SEG引脚电压
  48. COM引脚电压为VCC,SEG引脚电压为VCC,交替后,则为COM引脚电压为0,SEG引脚电压为0;
  49. 只要COM引脚和SEG引脚的电压差为+VCC或者-VCC,就可以点亮对应的LCD笔段即像素点,具体实现步骤如下:
  50. 第1次中断时设置COM0引脚输出High,其它COM引脚输出VDD/2,再根据要显示的数据设置各个SEG的输出;
  51. 第2次中断时设置COM0引脚输出Low,其它COM引脚输出VDD/2,再根据要显示的数据设置各个SEG的输出;
  52. 第3次中断时设置COM1引脚输出High,其它COM引脚输出VDD/2,再根据要显示的数据设置各个SEG的输出;
  53. 第4次中断时设置COM1引脚输出Low,其它COM引脚输出VDD/2,再根据要显示的数据设置各个SEG的输出;
  54. 第5次中断时设置COM2引脚输出High,其它COM引脚输出VDD/2,再根据要显示的数据设置各个SEG的输出;
  55. 第6次中断时设置COM2引脚输出Low,其它COM引脚输出VDD/2,再根据要显示的数据设置各个SEG的输出;
  56. 循环进行以上的6次循环设置,即可完成“使用单片机IO模拟驱动段码LCD”;
  57. */
  58. unsigned char Scan_SegmentCodeScreen_Counter;
  59. unsigned int wei1_num=NUM0;//个位上的数码管1显示数据
  60. unsigned int wei2_num=NUM0;//十位上的数码管1显示数据
  61. unsigned int wei3_num=NUM0;//百位上的数码管显示数据
  62. unsigned int wei4_num=NUM0;//千位上的数码管显示数据
  63. unsigned int timer_value;//计数器的值
  64. u16 Timer2MilliSecond;//毫秒计数器
  65. void TIM2_Interrupt_Initializtion(u16 arr,u16 psc);
  66. //函数功能:sel=1设置GPIOB13为输出口,sel=0,则设置GPIOB13为浮空输入
  67. void COM0_PIN_Configuration(u8 sel)
  68. {
  69. GPIO_InitTypeDef GPIO_InitStructure;
  70. if(sel==1)
  71. {
  72. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //选择第13脚
  73. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择推挽输出
  74. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO口的最高工作频率为50MHz
  75. GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
  76. }
  77. else
  78. {
  79. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //选择第13脚
  80. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  81. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO口的最高工作频率为50MHz
  82. GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
  83. }
  84. }
  85. //函数功能:sel=1设置GPIOB14为输出口,sel=0,则设置GPIOB14为浮空输入
  86. void COM1_PIN_Configuration(u8 sel)
  87. {
  88. GPIO_InitTypeDef GPIO_InitStructure;
  89. if(sel==1)
  90. {
  91. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; //选择第14脚
  92. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择推挽输出
  93. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO口的最高工作频率为50MHz
  94. GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
  95. }
  96. else
  97. {
  98. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; //选择第14脚
  99. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  100. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO口的最高工作频率为50MHz
  101. GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
  102. }
  103. }
  104. //函数功能:sel=1设置GPIOB15为输出口,sel=0,则设置GPIOB15为浮空输入
  105. void COM2_PIN_Configuration(u8 sel)
  106. {
  107. GPIO_InitTypeDef GPIO_InitStructure;
  108. if(sel==1)
  109. {
  110. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; //选择第15脚
  111. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择推挽输出
  112. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO口的最高工作频率为50MHz
  113. GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
  114. }
  115. else
  116. {
  117. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; //选择第15脚
  118. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  119. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO口的最高工作频率为50MHz
  120. GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
  121. }
  122. }
  123. //函数功能:设置GPIOB1为输出口
  124. void SEG1_PIN_Configuration(void)
  125. {
  126. GPIO_InitTypeDef GPIO_InitStructure;
  127. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //选择第1脚
  128. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择推挽输出
  129. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO口的最高工作频率为50MHz
  130. GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
  131. }
  132. //函数功能:设置GPIOB2为输出口
  133. void SEG2_PIN_Configuration(void)
  134. {
  135. GPIO_InitTypeDef GPIO_InitStructure;
  136. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //选择第2脚
  137. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择推挽输出
  138. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO口的最高工作频率为50MHz
  139. GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
  140. }
  141. //函数功能:设置GPIOB3为输出口
  142. void SEG3_PIN_Configuration(void)
  143. {
  144. GPIO_InitTypeDef GPIO_InitStructure;
  145. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //选择第3脚
  146. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择推挽输出
  147. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO口的最高工作频率为50MHz
  148. GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
  149. }
  150. //函数功能:设置GPIOB4为输出口
  151. void SEG4_PIN_Configuration(void)
  152. {
  153. GPIO_InitTypeDef GPIO_InitStructure;
  154. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //选择第4脚
  155. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择推挽输出
  156. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO口的最高工作频率为50MHz
  157. GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
  158. }
  159. //函数功能:设置GPIOB5为输出口
  160. void SEG5_PIN_Configuration(void)
  161. {
  162. GPIO_InitTypeDef GPIO_InitStructure;
  163. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //选择第5脚
  164. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择推挽输出
  165. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO口的最高工作频率为50MHz
  166. GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
  167. }
  168. //函数功能:设置GPIOB6为输出口
  169. void SEG6_PIN_Configuration(void)
  170. {
  171. GPIO_InitTypeDef GPIO_InitStructure;
  172. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //选择第6脚
  173. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择推挽输出
  174. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO口的最高工作频率为50MHz
  175. GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
  176. }
  177. //函数功能:设置GPIOB7为输出口
  178. void SEG7_PIN_Configuration(void)
  179. {
  180. GPIO_InitTypeDef GPIO_InitStructure;
  181. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //选择第7脚
  182. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择推挽输出
  183. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO口的最高工作频率为50MHz
  184. GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
  185. }
  186. //函数功能:设置GPIOB8为输出口
  187. void SEG8_PIN_Configuration(void)
  188. {
  189. GPIO_InitTypeDef GPIO_InitStructure;
  190. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //选择第8脚
  191. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择推挽输出
  192. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO口的最高工作频率为50MHz
  193. GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
  194. }
  195. //函数功能:设置GPIOB9为输出口
  196. void SEG9_PIN_Configuration(void)
  197. {
  198. GPIO_InitTypeDef GPIO_InitStructure;
  199. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //选择第9脚
  200. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择推挽输出
  201. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO口的最高工作频率为50MHz
  202. GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
  203. }
  204. //函数功能:设置GPIOB10为输出口
  205. void SEG10_PIN_Configuration(void)
  206. {
  207. GPIO_InitTypeDef GPIO_InitStructure;
  208. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //选择第10脚
  209. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择推挽输出
  210. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO口的最高工作频率为50MHz
  211. GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
  212. }
  213. //函数功能:设置GPIOB11为输出口
  214. void SEG11_PIN_Configuration(void)
  215. {
  216. GPIO_InitTypeDef GPIO_InitStructure;
  217. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //选择第11脚
  218. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择推挽输出
  219. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO口的最高工作频率为50MHz
  220. GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
  221. }
  222. //函数功能:设置GPIOB12为输出口
  223. void SEG12_PIN_Configuration(void)
  224. {
  225. GPIO_InitTypeDef GPIO_InitStructure;
  226. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //选择第12脚
  227. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择推挽输出
  228. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO口的最高工作频率为50MHz
  229. GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
  230. }
  231. void SegmentCodeScreen_Init(void)
  232. {
  233. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能GPIOB的外设时钟
  234. COM0_PIN_Configuration(0);
  235. COM1_PIN_Configuration(0);
  236. COM2_PIN_Configuration(0);
  237. SEG1_PIN_Configuration();
  238. SEG2_PIN_Configuration();
  239. SEG3_PIN_Configuration();
  240. SEG4_PIN_Configuration();
  241. SEG5_PIN_Configuration();
  242. SEG6_PIN_Configuration();
  243. SEG7_PIN_Configuration();
  244. SEG8_PIN_Configuration();
  245. SEG9_PIN_Configuration();
  246. SEG10_PIN_Configuration();
  247. SEG11_PIN_Configuration();
  248. SEG12_PIN_Configuration();
  249. }
  250. void SegmentCodeScreen_Work(void)//定时器配置5ms扫描一次即可
  251. {
  252. Scan_SegmentCodeScreen_Counter++;//下一位
  253. if(Scan_SegmentCodeScreen_Counter>5)//扫描完一轮才更新数值
  254. {
  255. Scan_SegmentCodeScreen_Counter=0;
  256. switch(timer_value%10000/1000)//求千位数
  257. {
  258. case 0: wei4_num=NUM0; break;
  259. case 1: wei4_num=NUM1; break;
  260. case 2: wei4_num=NUM2; break;
  261. case 3: wei4_num=NUM3; break;
  262. case 4: wei4_num=NUM4; break;
  263. case 5: wei4_num=NUM5; break;
  264. case 6: wei4_num=NUM6; break;
  265. case 7: wei4_num=NUM7; break;
  266. case 8: wei4_num=NUM8; break;
  267. case 9: wei4_num=NUM9; break;
  268. }
  269. switch(timer_value%1000/100)//求百位数
  270. {
  271. case 0: wei3_num=NUM0; break;
  272. case 1: wei3_num=NUM1; break;
  273. case 2: wei3_num=NUM2; break;
  274. case 3: wei3_num=NUM3; break;
  275. case 4: wei3_num=NUM4; break;
  276. case 5: wei3_num=NUM5; break;
  277. case 6: wei3_num=NUM6; break;
  278. case 7: wei3_num=NUM7; break;
  279. case 8: wei3_num=NUM8; break;
  280. case 9: wei3_num=NUM9; break;
  281. }
  282. switch(timer_value%100/10)//求十位数
  283. {
  284. case 0: wei2_num=NUM0; break;
  285. case 1: wei2_num=NUM1; break;
  286. case 2: wei2_num=NUM2; break;
  287. case 3: wei2_num=NUM3; break;
  288. case 4: wei2_num=NUM4; break;
  289. case 5: wei2_num=NUM5; break;
  290. case 6: wei2_num=NUM6; break;
  291. case 7: wei2_num=NUM7; break;
  292. case 8: wei2_num=NUM8; break;
  293. case 9: wei2_num=NUM9; break;
  294. }
  295. switch(timer_value%10)//求个位数
  296. {
  297. case 0: wei1_num=NUM0; break;
  298. case 1: wei1_num=NUM1; break;
  299. case 2: wei1_num=NUM2; break;
  300. case 3: wei1_num=NUM3; break;
  301. case 4: wei1_num=NUM4; break;
  302. case 5: wei1_num=NUM5; break;
  303. case 6: wei1_num=NUM6; break;
  304. case 7: wei1_num=NUM7; break;
  305. case 8: wei1_num=NUM8; break;
  306. case 9: wei1_num=NUM9; break;
  307. }
  308. }
  309. switch(Scan_SegmentCodeScreen_Counter) //动态扫描
  310. {
  311. case 0: //COM0引脚正向驱动
  312. COM1_PIN_Configuration(0);//设置COM1引脚为输入浮空,COM1引脚因电阻分压得到电压为VDD/2
  313. COM2_PIN_Configuration(0);//设置COM2引脚为输入浮空,COM1引脚因电阻分压得到电压为VDD/2
  314. COM0_PIN_Configuration(1);//配置COM0引脚为输出口
  315. COM0=1;//COM0引脚电压为VCC,则要求SEGx引脚电压为0
  316. 千位上的数码管/
  317. if(wei4_num!=NUM0)
  318. {
  319. if(wei4_num&0x01) SEG1=0;else SEG1=1;
  320. if(wei4_num&0x02) SEG2=0;else SEG2=1;
  321. if(wei4_num&0x04) SEG3=0;else SEG3=1;
  322. }
  323. else{SEG1=1;SEG2=1;SEG3=1;}//不显示
  324. 百位上的数码管
  325. if(wei3_num&0x01) SEG4=0;else SEG4=1;
  326. if(wei3_num&0x02) SEG5=0;else SEG5=1;
  327. if(wei3_num&0x04) SEG6=0;else SEG6=1;
  328. 十位上的数码管
  329. if(wei2_num&0x01) SEG7=0;else SEG7=1;
  330. if(wei2_num&0x02) SEG8=0;else SEG8=1;
  331. if(wei2_num&0x04) SEG9=0;else SEG9=1;
  332. 个位上的数码管
  333. if(wei1_num&0x01) SEG10=0;else SEG10=1;
  334. if(wei1_num&0x02) SEG11=0;else SEG11=1;
  335. if(wei1_num&0x04) SEG12=0;else SEG12=1;
  336. break;
  337. case 1://COM0引脚反向驱动
  338. COM1_PIN_Configuration(0);//设置COM1引脚为输入浮空,COM1引脚因电阻分压得到电压为VDD/2
  339. COM2_PIN_Configuration(0);//设置COM2引脚为输入浮空,COM1引脚因电阻分压得到电压为VDD/2
  340. COM0_PIN_Configuration(1);//配置COM0引脚为输出口
  341. COM0=0;//COM0引脚电压为0,则SEGx引脚电压为VCC;
  342. 千位上的数码管/
  343. if(wei4_num&0x01) SEG1=1; else SEG1=0;
  344. if(wei4_num&0x02) SEG2=1; else SEG2=0;
  345. if(wei4_num&0x04) SEG3=1; else SEG3=0;
  346. 百位上的数码管
  347. if(wei4_num!=NUM0)
  348. {
  349. if(wei3_num&0x01) SEG4=1; else SEG4=0;
  350. if(wei3_num&0x02) SEG5=1; else SEG5=0;
  351. if(wei3_num&0x04) SEG6=1; else SEG6=0;
  352. }
  353. else{SEG1=0;SEG2=0;SEG3=0;}//不显示
  354. 十位上的数码管
  355. if(wei2_num&0x01) SEG7=1;else SEG7=0;
  356. if(wei2_num&0x02) SEG8=1;else SEG8=0;
  357. if(wei2_num&0x04) SEG9=1;else SEG9=0;
  358. 个位上的数码管
  359. if(wei1_num&0x01) SEG10=1;else SEG10=0;
  360. if(wei1_num&0x02) SEG11=1;else SEG11=0;
  361. if(wei1_num&0x04) SEG12=1;else SEG12=0;
  362. break;
  363. case 2://COM1引脚正向驱动
  364. COM0_PIN_Configuration(0);//除COM1输出外,其余COM设为输入
  365. COM2_PIN_Configuration(0);//除COM1输出外,其余COM设为输入
  366. COM1_PIN_Configuration(1);//配置COM1引脚为输出口
  367. COM1=1;//COM1引脚电压为VCC,则要求SEGx引脚电压为0
  368. 千位上的数码管/
  369. if(wei4_num!=NUM0)
  370. {
  371. if(wei4_num&0x08) SEG1=0; else SEG1=1;
  372. if(wei4_num&0x10) SEG2=0; else SEG2=1;
  373. if(wei4_num&0x20) SEG3=0; else SEG3=1;
  374. }
  375. else{SEG1=1;SEG2=1;SEG3=1;}//不显示
  376. 百位上的数码管
  377. if(wei3_num&0x08) SEG4=0;else SEG4=1;
  378. if(wei3_num&0x10) SEG5=0;else SEG5=1;
  379. if(wei3_num&0x20) SEG6=0;else SEG6=1;
  380. 十位上的数码管
  381. if(wei2_num&0x08) SEG7=0;else SEG7=1;
  382. if(wei2_num&0x10) SEG8=0;else SEG8=1;
  383. if(wei2_num&0x20) SEG9=0;else SEG9=1;
  384. 个位上的数码管
  385. if(wei1_num&0x08) SEG10=0;else SEG10=1;
  386. if(wei1_num&0x10) SEG11=0;else SEG11=1;
  387. if(wei1_num&0x20) SEG12=0;else SEG12=1;
  388. break;
  389. case 3://COM1引脚反向驱动
  390. COM0_PIN_Configuration(0);//除COM1输出外,其余COM设为输入
  391. COM2_PIN_Configuration(0);//除COM1输出外,其余COM设为输入
  392. COM1_PIN_Configuration(1);//配置COM1引脚为输出口
  393. COM1=0;//COM1引脚电压为0,则要求SEGx引脚电压为VCC
  394. 千位上的数码管/
  395. if(wei4_num!=NUM0)
  396. {
  397. if(wei4_num&0x08) SEG1=1; else SEG1=0;
  398. if(wei4_num&0x10) SEG2=1; else SEG2=0;
  399. if(wei4_num&0x20) SEG3=1; else SEG3=0;
  400. }
  401. else{SEG1=0;SEG2=0;SEG3=0;}//不显示
  402. 百位上的数码管
  403. if(wei3_num&0x08) SEG4=1;else SEG4=0;
  404. if(wei3_num&0x10) SEG5=1;else SEG5=0;
  405. if(wei3_num&0x20) SEG6=1;else SEG6=0;
  406. 十位上的数码管
  407. if(wei2_num&0x08) SEG7=1;else SEG7=0;
  408. if(wei2_num&0x10) SEG8=1;else SEG8=0;
  409. if(wei2_num&0x20) SEG9=1;else SEG9=0;
  410. 个位上的数码管
  411. if(wei1_num&0x08) SEG10=1;else SEG10=0;
  412. if(wei1_num&0x10) SEG11=1;else SEG11=0;
  413. if(wei1_num&0x20) SEG12=1;else SEG12=0;
  414. break;
  415. case 4:
  416. COM0_PIN_Configuration(0);//除COM2输出外,其余COM设为输入
  417. COM1_PIN_Configuration(0);//除COM2输出外,其余COM设为输入
  418. COM2_PIN_Configuration(1);//配置COM1引脚为输出口
  419. COM2=1;//COM2引脚电压为VCC,则要求SEGx引脚电压为0
  420. 千位上的数码管/
  421. if(wei4_num!=NUM0)
  422. {
  423. if(wei4_num&0x40) SEG1=0;else SEG1=1;
  424. if(wei4_num&0x80) SEG2=0;else SEG2=1;
  425. if(wei4_num&0x100) SEG3=0;else SEG3=1;
  426. }
  427. else{SEG1=1;SEG2=1;SEG3=1;}//不显示
  428. 百位上的数码管/
  429. if(wei3_num&0x40) SEG4=0;else SEG4=1;
  430. if(wei3_num&0x80) SEG5=0;else SEG5=1;
  431. if(wei3_num&0x100) SEG6=0;else SEG6=1;
  432. 十位上的数码管/
  433. if(wei2_num&0x40) SEG7=0;else SEG7=1;
  434. if(wei2_num&0x80) SEG8=0;else SEG8=1;
  435. if(wei2_num&0x100) SEG9=0;else SEG9=1;
  436. 个位上的数码管/
  437. if(wei1_num&0x40) SEG10=0;else SEG10=1;
  438. if(wei1_num&0x80) SEG11=0;else SEG11=1;
  439. if(wei1_num&0x100) SEG12=0;else SEG12=1;
  440. break;
  441. case 5:
  442. COM0_PIN_Configuration(0);//除COM2输出外,其余COM设为输入
  443. COM1_PIN_Configuration(0);//除COM2输出外,其余COM设为输入
  444. COM2_PIN_Configuration(1);//配置COM1引脚为输出口
  445. COM2=0;//COM2引脚电压为0,则要求SEGx引脚电压为VCC
  446. 千位上的数码管/
  447. if(wei4_num!=NUM0)
  448. {
  449. if(wei4_num&0x40) SEG1=1;else SEG1=0;
  450. if(wei4_num&0x80) SEG2=1;else SEG2=0;
  451. if(wei4_num&0x100) SEG3=1;else SEG3=0;
  452. }
  453. else{SEG1=0;SEG2=0;SEG3=0;}//不显示
  454. 百位上的数码管/
  455. if(wei3_num&0x40) SEG4=1;else SEG4=0;
  456. if(wei3_num&0x80) SEG5=1;else SEG5=0;
  457. if(wei3_num&0x100) SEG6=1;else SEG6=0;
  458. 十位上的数码管/
  459. if(wei2_num&0x40) SEG7=1;else SEG7=0;
  460. if(wei2_num&0x80) SEG8=1;else SEG8=0;
  461. if(wei2_num&0x100) SEG9=1;else SEG9=0;
  462. 个位上的数码管/
  463. if(wei1_num&0x40) SEG10=1;else SEG10=0;
  464. if(wei1_num&0x80) SEG11=1;else SEG11=0;
  465. if(wei1_num&0x100) SEG12=1;else SEG12=0;
  466. break;
  467. }
  468. }
  469. //通用定时器2中断初始化
  470. //这里时钟选择为APB1的2倍,而APB1为36M
  471. //arr:自动重装值。
  472. //psc:时钟预分频数
  473. //这里使用的是定时器2!
  474. //TIM2_Interrupt_Initializtion(1000,36);//当arr=1000,psc=36时,则为0.5ms,误差为0.5us;
  475. //TIM2_Interrupt_Initializtion(2000,36);//当arr=2000,psc=36时,则为1ms,误差为0.5us;
  476. //TIM2_Interrupt_Initializtion(4000,36);//当arr=4000,psc=36时,则为2ms,误差为0.5us;
  477. void TIM2_Interrupt_Initializtion(u16 arr,u16 psc)
  478. {
  479. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  480. NVIC_InitTypeDef NVIC_InitStructure;
  481. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能定时器TIM2的APB1外设时钟
  482. //定时器TIM2初始化
  483. TIM_TimeBaseStructure.TIM_Period = arr-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
  484. TIM_TimeBaseStructure.TIM_Prescaler =psc-1; //设置用来作为TIMx时钟频率除数的预分频值
  485. TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
  486. //计算公式:arr*psc/72000000/1,当arr=1000,psc=72时,则为1ms,误差为1us;
  487. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
  488. TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
  489. TIM_SetCounter(TIM2,0); //设置TIM2的计数器值为0;
  490. TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除TIM2溢出的待处理标志位
  491. TIM_ClearITPendingBit(TIM2, TIM_IT_Update ); //清除TIM2中断的待处理位
  492. TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); //允许TIM2溢出产生中断
  493. //中断优先级NVIC设置
  494. //NVIC_PriorityGroup_4设置NVIC中断分组4:表示抢占优先级为4位,取值为0~15,没有响应优先级,取值为0
  495. //NVIC_PriorityGroup_3设置NVIC中断分组3:表示抢占优先级为3位,取值为0~7,响应优先级只有1位,取值为0~1
  496. //NVIC_PriorityGroup_2设置NVIC中断分组3:表示抢占优先级为2位,取值为0~3,响应优先级只有2位,取值为0~3
  497. //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
  498. NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM2中断
  499. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 11; //设置抢占优先级为11
  500. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //设置响应优先级为0
  501. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
  502. NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化NVIC嵌套向量中断控制寄存器
  503. TIM_Cmd(TIM2, ENABLE);//使能TIM2外设
  504. SegmentCodeScreen_Init();
  505. Timer2MilliSecond=0;//毫秒计数器
  506. timer_value=0;
  507. }
  508. //函数功能:TIM2每1ms中断一次
  509. void TIM2_IRQHandler()
  510. {
  511. if (TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET) //TIM2计数器溢出产生中断
  512. {
  513. Timer2MilliSecond++;//毫秒计数器加1
  514. if(Timer2MilliSecond%5==0)//5毫秒时间到达
  515. {
  516. SegmentCodeScreen_Work();
  517. }
  518. if(Timer2MilliSecond%1000==0)//1秒时间到达
  519. {
  520. timer_value++;
  521. if(timer_value>999) timer_value=0;
  522. Timer2MilliSecond=0;
  523. }
  524. TIM_ClearITPendingBit(TIM2,TIM_IT_Update); //清除TIM2计数器的溢出中断标志;
  525. }
  526. }

7、SegmentCodeScreen.h

  1. #ifndef _SegmentCodeScreen_H
  2. #define _SegmentCodeScreen_H
  3. #include "stm32f10x.h"
  4. #include "sys.h"
  5. /*
  6. LCD引脚号码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  7. LCD引脚名字 COM0 COM1 COM2 SEG1 SEG2 SEG3 SEG4 SEG5 SEG6 SEG7 SEG8 SEG9 SEG10 SEG11 SEG12
  8. COM0 -- -- -- 1D -- -- 2D COL -- 3D -- -- 4D --
  9. -- COM1 -- 1E 1G 1C 2E 2G 2C 3E 3G 3C 4E 4G 4C
  10. -- -- COM2 1F 1A 1B 2F 2A 2B 3F 3A 3B 4F 4A 4B
  11. */
  12. /*
  13. 数码管1:
  14. COM0和SEG2控制数码管1的D段
  15. COM1和SEG1控制数码管1的E段
  16. COM1和SEG2控制数码管1的G段
  17. COM1和SEG3控制数码管1的C段
  18. COM2和SEG1控制数码管1的F段
  19. COM2和SEG2控制数码管1的A段
  20. COM2和SEG3控制数码管1的B段
  21. */
  22. #define COM0_SEG1_VALUE 0x01 //定义LCD引脚SEG1和COM0交点的值,对于数码管1来说,没有段
  23. #define COM0_SEG2_VALUE 0x02 //定义LCD引脚SEG2和COM0交点的值,即定义数码管1的D段
  24. #define COM0_SEG3_VALUE 0x04 //定义LCD引脚SEG3和COM0交点的值,对于数码管1来说,没有段
  25. #define COM1_SEG1_VALUE 0x08 //定义LCD引脚SEG1和COM1交点的值,即定义数码管1的E段
  26. #define COM1_SEG2_VALUE 0x10 //定义LCD引脚SEG2和COM1交点的值,即定义数码管1的G段
  27. #define COM1_SEG3_VALUE 0x20 //定义LCD引脚SEG3和COM1交点的值,即定义数码管1的C段
  28. #define COM2_SEG1_VALUE 0x40 //定义LCD引脚SEG1和COM2交点的值,即定义数码管1的F段
  29. #define COM2_SEG2_VALUE 0x80 //定义LCD引脚SEG2和COM2交点的值,即定义数码管1的A段
  30. #define COM2_SEG3_VALUE 0x100 //定义LCD引脚SEG3和COM2交点的值,即定义数码管1的B段
  31. /*
  32. 数码管2:
  33. COM0和SEG5控制数码管2的D段
  34. COM0和SEG6控制数码管2的COL段,即“:”
  35. COM1和SEG4控制数码管2的E段
  36. COM1和SEG5控制数码管2的G段
  37. COM1和SEG6控制数码管2的C段
  38. COM2和SEG4控制数码管2的F段
  39. COM2和SEG5控制数码管2的A段
  40. COM2和SEG3控制数码管6的B段
  41. */
  42. #define COM0_SEG4_VALUE 0x01 //定义LCD引脚SEG4和COM0交点的值,对于数码管2来说,没有段
  43. #define COM0_SEG5_VALUE 0x02 //定义LCD引脚SEG5和COM0交点的值,即定义数码管2的D段
  44. #define COM0_SEG6_VALUE 0x04 //定义LCD引脚SEG6和COM0交点的值,即定义数码管2的COL段
  45. #define COM1_SEG4_VALUE 0x08 //定义LCD引脚SEG4和COM1交点的值,即定义数码管2的E段
  46. #define COM1_SEG5_VALUE 0x10 //定义LCD引脚SEG5和COM1交点的值,即定义数码管2的G段
  47. #define COM1_SEG6_VALUE 0x20 //定义LCD引脚SEG6和COM1交点的值,即定义数码管2的C段
  48. #define COM2_SEG4_VALUE 0x40 //定义LCD引脚SEG4和COM2交点的值,即定义数码管2的F段
  49. #define COM2_SEG5_VALUE 0x80 //定义LCD引脚SEG5和COM2交点的值,即定义数码管2的A段
  50. #define COM2_SEG6_VALUE 0x100 //定义LCD引脚SEG6和COM2交点的值,即定义数码管2的B段
  51. /*
  52. 数码管3:
  53. COM0和SEG8控制数码管3的D段
  54. COM1和SEG7控制数码管3的E段
  55. COM1和SEG8控制数码管3的G段
  56. COM1和SEG9控制数码管3的C段
  57. COM2和SEG7控制数码管3的F段
  58. COM2和SEG8控制数码管3的A段
  59. COM2和SEG9控制数码管3的B段
  60. */
  61. #define COM0_SEG7_VALUE 0x01 //定义LCD引脚SEG7和COM0交点的值,对于数码管3来说,没有段
  62. #define COM0_SEG8_VALUE 0x02 //定义LCD引脚SEG8和COM0交点的值,即定义数码管3的D段
  63. #define COM0_SEG9_VALUE 0x04 //定义LCD引脚SEG9和COM0交点的值,对于数码管3来说,没有段
  64. #define COM1_SEG7_VALUE 0x08 //定义LCD引脚SEG7和COM1交点的值,即定义数码管3的E段
  65. #define COM1_SEG8_VALUE 0x10 //定义LCD引脚SEG8和COM1交点的值,即定义数码管3的G段
  66. #define COM1_SEG9_VALUE 0x20 //定义LCD引脚SEG9和COM1交点的值,即定义数码管3的C段
  67. #define COM2_SEG7_VALUE 0x40 //定义LCD引脚SEG7和COM2交点的值,即定义数码管3的F段
  68. #define COM2_SEG8_VALUE 0x80 //定义LCD引脚SEG8和COM2交点的值,即定义数码管3的A段
  69. #define COM2_SEG9_VALUE 0x100 //定义LCD引脚SEG9和COM2交点的值,即定义数码管3的B段
  70. /*
  71. 数码管4:
  72. COM0和SEG11控制数码管4的D段
  73. COM1和SEG10控制数码管4的E段
  74. COM1和SEG11控制数码管4的G段
  75. COM1和SEG12控制数码管4的C段
  76. COM2和SEG10控制数码管4的F段
  77. COM2和SEG11控制数码管4的A段
  78. COM2和SEG12控制数码管4的B段
  79. */
  80. #define COM0_SEG10_VALUE 0x01 //定义LCD引脚SEG10和COM0交点的值,对于数码管4来说,没有段
  81. #define COM0_SEG11_VALUE 0x02 //定义LCD引脚SEG11和COM0交点的值,即定义数码管4的D段
  82. #define COM0_SEG12_VALUE 0x04 //定义LCD引脚SEG12和COM0交点的值,对于数码管4来说,没有段
  83. #define COM1_SEG10_VALUE 0x08 //定义LCD引脚SEG10和COM1交点的值,即定义数码管4的E段
  84. #define COM1_SEG11_VALUE 0x10 //定义LCD引脚SEG11和COM1交点的值,即定义数码管4的G段
  85. #define COM1_SEG12_VALUE 0x20 //定义LCD引脚SEG12和COM1交点的值,即定义数码管4的C段
  86. #define COM2_SEG10_VALUE 0x40 //定义LCD引脚SEG10和COM2交点的值,即定义数码管4的F段
  87. #define COM2_SEG11_VALUE 0x80 //定义LCD引脚SEG11和COM2交点的值,即定义数码管4的A段
  88. #define COM2_SEG12_VALUE 0x100 //定义LCD引脚SEG12和COM2交点的值,即定义数码管4的B段
  89. /*
  90. -----A----
  91. | |
  92. F B
  93. | |
  94. ----G ---
  95. | |
  96. E C
  97. | | _
  98. -----D---- | |COL
  99. -
  100. 根据上述定义,我们发现如下规律:
  101. 数码管的A段用0x80表示
  102. 数码管的B段用0x100表示
  103. 数码管的C段用0x20表示
  104. 数码管的D段用0x02表示
  105. 数码管的E段用0x08表示
  106. 数码管的F段用0x40表示
  107. 数码管的G段用0x10表示
  108. 数码管的COL段用0x04表示
  109. */
  110. #define NUM0 0x01EF//A段+B段+C段+D段+E段+F段 = 0x80+0x100+0x20+0x02+0x08+0x40
  111. #define NUM1 0x0120//B段+C段 = 0x100+0x20
  112. #define NUM2 0x019A//A段+B段+G段+E段+D段 = 0x80+0x100+0x10+0x08+0x02
  113. #define NUM3 0x01B2//A段+B段+G段+C段+D段 = 0x80+0x100+0x10+0x20+0x02
  114. #define NUM4 0x0170//F段+G段+B段+C段 = 0x40+0x10+0x100+0x20
  115. #define NUM5 0x00F2//A段+F段+G段+C段+D段 = 0x80+0x40+0x10+0x20+0x02
  116. #define NUM6 0x00FA//A段+F段+E段+D段+C段+G段 = 0x80+0x40+0x08+0x02+0x20+0x10
  117. #define NUM7 0x01A0//A段+B段+C段 = 0x80+0x100+0x20
  118. #define NUM8 0x01FA//A段+B段+C段+D段+E段+F段+G段 =0x80+0x100+0x20+0x02+0x08+0x40+0x10
  119. #define NUM9 0x01F2//A段+B段+C段+D段+F段+G段 =0x80+0x100+0x20+0x02+0x40+0x10
  120. //CPU引脚定义///
  121. #define SEG1 PBout(1) //PB1
  122. #define SEG2 PBout(2) //PB2
  123. #define SEG3 PBout(3) //PB3
  124. #define SEG4 PBout(4) //PB4
  125. #define SEG5 PBout(5) //PB5
  126. #define SEG6 PBout(6) //PB6
  127. #define SEG7 PBout(7) //PB7
  128. #define SEG8 PBout(8) //PB8
  129. #define SEG9 PBout(9) //PB9
  130. #define SEG10 PBout(10) //PB10
  131. #define SEG11 PBout(11) //PB11
  132. #define SEG12 PBout(12) //PB12
  133. #define COM0 PBout(13) //PB13
  134. #define COM1 PBout(14) //PB14
  135. #define COM2 PBout(15) //PB15
  136. extern void TIM2_Interrupt_Initializtion(u16 arr,u16 psc);
  137. #endif

8、使用单片机IO直接驱动偏压比为1/3的段码屏,驱动和显示原理如下:

段码屏驱动条件: 3.3V, 1/4Duty, 1/3Bias

视角: 6
温度范围: -20~70度工作


本文转载自: https://blog.csdn.net/weixin_42550185/article/details/138656769
版权归原作者 LaoZhangGong123 所有, 如有侵权,请联系我们删除。

“使用单片机的IO引脚直接驱动段码屏”的评论:

还没有评论