作为一个初学者第一次做项目就把目光放在了不需要什么传感器的数码管上,上手后才发现还是有点难度的,首先数码管与单片机直连需要消耗的资源太多,所以选择了用74HC138作为段选器选择哪一位数码管亮,用74HC595芯片作为数码管的位选选择其段码。
管脚号 | 管脚名称 | 作用 |
1 ~ 7,15 | Q1~Q7,Q15 | 输出端 |
8 | GED | 电源地 |
9 | Q7S | 级联输出,与下一个595 DS段连接 |
10 | MR | 清除移位寄存器数据(低电平有效),一般不用 |
11 | SHCP | 此引脚上升沿时,移位寄存器后移,接收新数据 |
12 | STCP | 上升沿时数据放进存储寄存器 |
13 | OE | 使能控制(低电平有效) |
14 | DS | 数据写入端 |
16 | VCC | 供电端 |
138译码器,就是把 3 种输入状态翻译成 8 种输出状态。从图所能看出来的74HC138 有 1~6 一共是 6 个输入引脚, 4,5,6 是使能引脚。Y0 到 Y7 为输出引脚。
引脚定义
引脚号 | 引脚名称 | 作用 |
1,2,3 | A0,A1,A2 | 输入引脚 |
4,5 | E1,E2 | 使能引脚(低电平有效) |
6 | E3 | 使能引脚(高电平有效) |
7,9 ~ 15 | Y0 ~ Y7 | 输出引脚 |
8 | GND | 电源地 |
16 | VCC | 电源 |
电路图如下所示
OK接下来是段选时间!! 当我们要选择第七位时 转换成二进制是0111,A0 = 0111&0x01取最后一位给A0,A1 = 0111 & 0x01 >> 1将第二位送给A1引脚 A2 = 0111 & 0x03 >> 2;将第三位送到A2引脚 可以定义一个子函数专门用来处理段选的数据 nod为选择的段位
void SHUMAGUAN_DUANXUAN_MOD(u8 nod)
{
SEG_A0= nod&0x01;
SEG_A1= (nod&0x02)>>1;
SEG_A2= (nod&0x04)>>2;
}
段选搞定了后就要向这个位发送数据啦,在介绍74HC595芯片里了解到想要向寄存器中写入数据要先写入移位寄存器。所以在写入数据后需要手动给SHCP一个上升沿写入一位给一次
for(i=0;i<8;i++)
{
SEG_DATA = (dat>>i)&0x01;
SEG_SCK=0;
Delay10us();
SEG_SCK=1;
}
经过8次循环数据已经完整的写入移位寄存器 现在需要将移位寄存器的值放入到存储器中手动给STCP引脚一个上升沿。这就是完整的写数据步骤。
以下是我的程序段:定义了一个数组用来存放每一位的段码值需要改变数据时 只要更新数组里的值就可以。
u8 SEG8_Code[] ={
0xFC, // 0
0x60, // 1
0xDA, // 2
0xF2, // 3
0x66, // 4
0xB6, // 5
0xBE, // 6
0xE0, // 7
0xFE, // 8
0xF6, // 9
0xEE, // A
0x3E, // b
0x9C, // C
0x7A, // d
0x9E, // E
0x8E, // F
};
//断码显示数组
u8 SEG8_DispArray[8] ={0xFC,0xFC,0x02,0xFC,0xFC,0x02,0xFC,0xFC};
//初始化
void LEDseg_init(void)
{
P3M1 &= 0xCB; P3M0 |= 0x34; //数据口推挽输出
P4M1 &= 0xEE; P4M0 &= 0xEE; //段选口双向输入
P5M1 &= 0xDF; P5M0 &= 0xDF; //P5.5双向输入
SEG_A0=1;
SEG_A1=1;
SEG_A2=1;
SEG_LCLK=1;
SEG_SCK=0;
SEG_DATA=0;
}
//段选 7 = 0111;
void SHUMAGUAN_DUANXUAN_MOD(u8 nod)
{
SEG_A0= nod&0x01;
SEG_A1= (nod&0x02)>>1;
SEG_A2= (nod&0x04)>>2;
}
//写数据 将数据以移位的方式写入DS引脚 DS(数据引脚) SCK引脚上升沿时接收新数据
void SHUMAGUAN_WRITE_MOD(u8 nod)
{
u8 dat,i;
dat = SEG8_DispArray[nod];
for(i=0;i<8;i++)
{
SEG_DATA = (dat>>i)&0x01;
SEG_SCK=0;
Delay10us();
SEG_SCK=1;
}
SHUMAGUAN_DUANXUAN_MOD(nod);
}
//更新数组里的数据
void SHUMAGUAN_Updata_MOD(u8 nod,u8 dat,u8 dp)
{
EA = 0;
SEG8_DispArray[nod] = SEG8_Code[dat] | dp;
EA = 1;
}
//数据存储到存储器中上升沿有效
void CUNFANG(void)
{
SEG_LCLK=1;
Delay10us();
SEG_LCLK=0;
}
//驱动数码管步骤 :写数据 (SCK引脚上升沿有效) 存储数据 (RCK上升沿有效)
void LEDseg_loop(void)
{
SHUMAGUAN_WRITE_MOD(ledseg_nod);
CUNFANG();
ledseg_nod++;
if(ledseg_nod == 8)ledseg_nod = 0;
}
数码管解决了按键直接一套消抖小连招送上,上电测试后发现消抖会用到延时函数,占用CPU按下按键时定时器时停止工作装态的,后面试了外部中断去掉抖动的延时发现按键不灵敏了,后来看江科大的视频发现可以使用一个定时器来扫描这些函数具体的实现过程是,定义一个定时器,定时器不断地扫描数码管,按键,如果按键有按下它当前的状态一定是高电平,它过去的状态一定是低电平所以只需要增加一个条件判断就可以去掉delay函数
unsigned char key_read(void)
{
unsigned char temp = 0;
temp = key_flag;
return temp;
}
//按下哪个按键
u8 buttons_scan(void)
{
unsigned char keynum;
keynum = 0;
if(BUTTON1_P37 == BUTTON_PRESSED )
{
keynum = 1;
}
if(BUTTON2_P36 == BUTTON_PRESSED)
{
keynum = 2;
}
return keynum;
}
//按键按下判断
void button_loop(void)
{
static unsigned char last_state =0, now_state =0;
last_state = now_state;
now_state = buttons_scan();
if(now_state == 0 && last_state == 1)
key_flag = 1;
if(now_state == 0 && last_state == 2)
key_flag = 2;
}
最后再用定时器不断调用 unsigned char key_read(void)函数就完美解决占用CPU资源的问题