相信玩过单片机的人都不会对数码管感到陌生!这次的分享也是近期在做的一个小项目里面用到的实例,代码均是自编、自测,保质保量?相信对各位初学者能起到快速上手的作用。(主控基于STM32F103ZCT6)。
俗话说的好,“工欲善其事,必先利其器”,在我们最先开始学习数码管的编程时,要先了解数码管的分类,数码管也称LED数码管,不同行业人士对数码管的称呼不一样,其实都是同样的产品。按发光二极管单元连接方式可分为共阳极数码管和共阴极数码管。共阳数码管是指将所有发光二极管的阳极接到一起形成公共阳极(COM)的数码管,共阳数码管在应用时应将公共极COM接到+5V,当某一字段发光二极管的阴极为低电平时,相应字段就点亮,当某一字段的阴极为高电平时,相应字段就不亮。共阴数码管是指将所有发光二极管的阴极接到一起形成公共阴极(COM)的数码管,共阴数码管在应用时应将公共极COM接到地线GND上,当某一字段发光二极管的阳极为高电平时,相应字段就点亮,当某一字段的阳极为低电平时,相应字段就不亮。其实还蛮好理解的?
数码管要正常显示,就要用驱动电路来驱动数码管的各个段码,从而显示出我们要的数字,因此根据数码管的驱动方式的不同,可以分为静态式和动态式两类。
静态显示驱动
静态驱动也称直流驱动。静态驱动是指每个数码管的每一个段码都由一个单片机的I/O端口进行驱动,或者使用如BCD码二-十进制译码器译码进行驱动。静态驱动的优点是编程简单,显示亮度高,缺点是占用I/O端口多,如驱动5个数码管静态显示则需要5×8=40根I/O端口来驱动,要知道一个89S51单片机可用的I/O端口才32个,实际应用时必须增加译码驱动器进行驱动,增加了硬件电路的复杂性。
动态显示驱动
数码管动态显示接口是单片机中应用最为广泛的一种显示方式之一,动态驱动是将所有数码管的8个显示划"a,b,c,d,e,f,g,dp"的同名端连在一起,另外为每个数码管的公共极COM增加位选通控制电路,位选通由各自独立的I/O线控制,当单片机输出字形码时,所有数码管都接收到相同的字形码,但究竟是哪个数码管会显示出字形,取决于单片机对位选通COM端电路的控制,所以我们只要将需要显示的数码管的选通控制打开,该位就显示出字形,没有选通的数码管就不会亮。通过分时轮流控制各个数码管的的COM端,就使各个数码管轮流受控显示,这就是动态驱动。在轮流显示过程中,每位数码管的点亮时间为1~2ms,由于人的视觉暂留现象及发光二极管的余辉效应,尽管实际上各位数码管并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示数据,不会有闪烁感,动态显示的效果和静态显示是一样的,能够节省大量的I/O端口,而且功耗更低。
在给出代码之前还需给出共阳数码管和主控的原理图,这样大家才看的清楚。
安拉安拉,相信刚才上面的一堆理论大家已经看烦了,那么我们现在直奔主题吧!(本次编译的是共阳数码管,大家别弄混哦!)好了,上代码!!!!
#include "shumaguan.h"
#include "stm32f10x.h"
void shumaguan(int i,int j)//定义共阳数码管控制函数,参数1为位选,参数2为段选;
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG,ENABLE);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOF, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOG, &GPIO_InitStructure); //初始化端口引脚;
switch(i)//开位选;
{
case 1:GPIO_SetBits(GPIOF,GPIO_Pin_13);break;
case 2:GPIO_SetBits(GPIOG,GPIO_Pin_0);break;
case 3:GPIO_SetBits(GPIOE,GPIO_Pin_9);break;
case 4:GPIO_SetBits(GPIOF,GPIO_Pin_12);break;
case 5:GPIO_SetBits(GPIOE,GPIO_Pin_8);break;
case 6:GPIO_SetBits(GPIOE,GPIO_Pin_7);break;
case 7:GPIO_SetBits(GPIOE,GPIO_Pin_10);break;
case 8:GPIO_SetBits(GPIOF,GPIO_Pin_11);break;
}
if (j==0)//匹配段选;
{
GPIO_SetBits(GPIOG,GPIO_Pin_8);
GPIO_SetBits(GPIOC,GPIO_Pin_6);
GPIO_ResetBits(GPIOC,GPIO_Pin_7);
GPIO_ResetBits(GPIOG,GPIO_Pin_4);
GPIO_ResetBits(GPIOG,GPIO_Pin_5);
GPIO_ResetBits(GPIOG,GPIO_Pin_6);
GPIO_ResetBits(GPIOG,GPIO_Pin_7);
}
else if(j==1)
{
GPIO_SetBits(GPIOG,GPIO_Pin_8);
GPIO_SetBits(GPIOC,GPIO_Pin_6);
GPIO_SetBits(GPIOC,GPIO_Pin_7);
GPIO_SetBits(GPIOA,GPIO_Pin_8);
GPIO_SetBits(GPIOG,GPIO_Pin_4);
GPIO_ResetBits(GPIOG,GPIO_Pin_5);
GPIO_ResetBits(GPIOG,GPIO_Pin_6);
GPIO_SetBits(GPIOG,GPIO_Pin_7);
}
else if(j==2)
{
GPIO_SetBits(GPIOG,GPIO_Pin_8);
GPIO_ResetBits(GPIOC,GPIO_Pin_6);
GPIO_SetBits(GPIOC,GPIO_Pin_7);
GPIO_ResetBits(GPIOA,GPIO_Pin_8);
GPIO_ResetBits(GPIOG,GPIO_Pin_4);
GPIO_SetBits(GPIOG,GPIO_Pin_5);
GPIO_ResetBits(GPIOG,GPIO_Pin_6);
GPIO_ResetBits(GPIOG,GPIO_Pin_7);
}
else if(j==3)
{
GPIO_SetBits(GPIOG,GPIO_Pin_8);
GPIO_ResetBits(GPIOC,GPIO_Pin_6);
GPIO_SetBits(GPIOC,GPIO_Pin_7);
GPIO_SetBits(GPIOA,GPIO_Pin_8);
GPIO_ResetBits(GPIOG,GPIO_Pin_4);
GPIO_ResetBits(GPIOG,GPIO_Pin_5);
GPIO_ResetBits(GPIOG,GPIO_Pin_6);
GPIO_ResetBits(GPIOG,GPIO_Pin_7);
}
else if(j==4)
{
GPIO_SetBits(GPIOG,GPIO_Pin_8);
GPIO_ResetBits(GPIOC,GPIO_Pin_6);
GPIO_ResetBits(GPIOC,GPIO_Pin_7);
GPIO_SetBits(GPIOA,GPIO_Pin_8);
GPIO_SetBits(GPIOG,GPIO_Pin_4);
GPIO_ResetBits(GPIOG,GPIO_Pin_5);
GPIO_ResetBits(GPIOG,GPIO_Pin_6);
GPIO_SetBits(GPIOG,GPIO_Pin_7);
}
else if(j==5)
{
GPIO_SetBits(GPIOG,GPIO_Pin_8);
GPIO_ResetBits(GPIOC,GPIO_Pin_6);
GPIO_ResetBits(GPIOC,GPIO_Pin_7);
GPIO_SetBits(GPIOA,GPIO_Pin_8);
GPIO_ResetBits(GPIOG,GPIO_Pin_4);
GPIO_ResetBits(GPIOG,GPIO_Pin_5);
GPIO_SetBits(GPIOG,GPIO_Pin_6);
GPIO_ResetBits(GPIOG,GPIO_Pin_7);
}
else if(j==6)
{
GPIO_SetBits(GPIOG,GPIO_Pin_8);
GPIO_ResetBits(GPIOC,GPIO_Pin_6);
GPIO_ResetBits(GPIOC,GPIO_Pin_7);
GPIO_ResetBits(GPIOA,GPIO_Pin_8);
GPIO_ResetBits(GPIOG,GPIO_Pin_4);
GPIO_ResetBits(GPIOG,GPIO_Pin_5);
GPIO_SetBits(GPIOG,GPIO_Pin_6);
GPIO_ResetBits(GPIOG,GPIO_Pin_7);
}
else if(j==7)
{
GPIO_SetBits(GPIOG,GPIO_Pin_8);
GPIO_SetBits(GPIOC,GPIO_Pin_6);
GPIO_SetBits(GPIOC,GPIO_Pin_7);
GPIO_SetBits(GPIOA,GPIO_Pin_8);
GPIO_SetBits(GPIOG,GPIO_Pin_4);
GPIO_ResetBits(GPIOG,GPIO_Pin_5);
GPIO_ResetBits(GPIOG,GPIO_Pin_6);
GPIO_ResetBits(GPIOG,GPIO_Pin_7);
}
else if(j==8)
{
GPIO_SetBits(GPIOG,GPIO_Pin_8);
GPIO_ResetBits(GPIOC,GPIO_Pin_6);
GPIO_ResetBits(GPIOC,GPIO_Pin_7);
GPIO_ResetBits(GPIOA,GPIO_Pin_8);
GPIO_ResetBits(GPIOG,GPIO_Pin_4);
GPIO_ResetBits(GPIOG,GPIO_Pin_5);
GPIO_ResetBits(GPIOG,GPIO_Pin_6);
GPIO_ResetBits(GPIOG,GPIO_Pin_7);
}
else if(j==9)
{
GPIO_ResetBits(GPIOG,GPIO_Pin_8);
GPIO_SetBits(GPIOC,GPIO_Pin_6);
GPIO_SetBits(GPIOC,GPIO_Pin_7);
GPIO_SetBits(GPIOA,GPIO_Pin_8);
GPIO_SetBits(GPIOG,GPIO_Pin_4);
GPIO_SetBits(GPIOG,GPIO_Pin_5);
GPIO_SetBits(GPIOG,GPIO_Pin_6);
GPIO_SetBits(GPIOG,GPIO_Pin_7);
}
switch(i)//关段选;
{
case 1:GPIO_ResetBits(GPIOF,GPIO_Pin_13);break;
case 2:GPIO_ResetBits(GPIOG,GPIO_Pin_0);break;
case 3:GPIO_ResetBits(GPIOE,GPIO_Pin_9);break;
case 4:GPIO_ResetBits(GPIOF,GPIO_Pin_12);break;
case 5:GPIO_ResetBits(GPIOE,GPIO_Pin_8);break;
case 6:GPIO_ResetBits(GPIOE,GPIO_Pin_7);break;
case 7:GPIO_ResetBits(GPIOE,GPIO_Pin_10);break;
case 8:GPIO_ResetBits(GPIOF,GPIO_Pin_11);break;
}
}
由于本人的性格原因,总是喜欢把代码往复杂了写?(自认为有可靠感)大家看完这段代码后可以直接定义自己的宏定义来修改代码的篇幅因为本段代码中有许多地方可以用宏定义后替代冗杂的代码,根据大家的喜好来吧,(因为本次代码是从一个整体项目中摘出来的,其中定义端口包含了本次项目其他跟本次数码管无关的初始化,大家自己删除即可)
显而易见,这段程序定义的函数第一个参数就是位选,这边板子上位选为高电平才会被选中,而第二个参数段选就按共阳数码管的规则来,低电平选中即可。封装成函数是为了以后编程32时工程调用方便,GPIO_ResetBits()和GPIO_SetBits()这两个函数作用就是具体到某个端口置0还是1的。。。有过32
编程基础的基本都懂?所以就不赘述了。