基于串行同步接口的数码管显示
由于一位数码管的驱动需要8个并行IO口进行输出,若驱动多位数码管则对单片机管脚的需求量过大,所以采用了74HC164芯片将串行数据并行输出,满足驱动数码管的要求。
74HC164是一种可以将串行数据并行输出的芯片,其芯片和原理图如下。
Q0-Q7为八个并行数据输出管脚;
VCC 接 MPS430G2553 的 +3.3V 电源;
GND 接地;
CP(CLK) 为 74HC164 的时钟,主要靠 MSP430G2553单片机提供;
DSA、DSB 为数据输入端;
MR 为 74HC164 的使能端。
下图为 74HC164 的功能表和时序图
功能表中"X"为任意态,即数据可以是0,也可以是1;
箭头为上升沿,即时钟拉高的一瞬间。
根据功能表可以看出,当使能MR为低电平时,无论CLK、A、B取什么值,输出都为0b0000_0000,即0x00,输出不受输入的影响。当使能MR为高电平时,时钟CLK会影响输出。当CLK为低电平时,输出恒为0x00,当检测到时钟的上升沿时,输出跟数据A、B有关。当A、B同时为“1”时,Q0置一,其余位数右移一位。当A、B中有一个为“0”时,无论另一个是多少,Q0都置零,其余位右移一位。
在实际操作中,由于数据端口A、B同时为“1”时才输出“1”,一者为“0”时便输出“0”,所以将A、B连接,使其两者数据相等,也能实现数据的传输。
为了方便74HC164与数码管的连接,采用了下表的对应关系。
下面为基于MSP430G2553单片机,采用串行同步接口驱动一位数码管的程序。
P1.7 做数据管脚,P1.6 做同步时钟管脚
其中 BIT0 = 0b0000_0001;
BIT1 = 0b0000_0010;
以此类推,
BIT6 = 0b0100_0000;
BIT7 = 0b1000_0000;
#include<msp430.h> // 包含名称定义和对应地址或数据的头函数
void delay_1s(void); // 声明 1s 延迟函数
void seg7_1ms(unsigned char seg7_data); // 声明驱动 1 位数码管的同步串行数据接口驱动函数
const unsigned char decoder_seg7[10] // 声明显示代码
={0xee,0x82,0xdc,0xd6,0xb2,0x76,0x7e,0xc2,0xfe,0xf6};
// 共阴极数码管显示代码
// MSP430 的 SPI 输出数据位顺序为高位在前,低位在后
// 74164 与 数码管的连接顺序为:Q0--dp
// Q1--c
// Q2--d
// Q3--e
// Q4--g
// Q5--f
// Q6--a
// Q7--b
int main(void) // 主函数
{
unsigned char data_seg7; // 声明显示数据变量
WDTCTL=WDTPW+WDTHOLD; // 关闭看门狗
P1SEL&=~BIT7; // 设置 P1.7 端口为并行数字输入 / 输出口
P1DIR|=BIT7; // 设置 P1.7 端口为输出口
P1SEL&=~BIT6; // 设置 P1.6 端口为并行数字输入 / 输出口
P1DIR|=BIT6; // 设置 P1.6 端口为输出口
while(1) // 重复执行
{
for(data_seg7=0; data_seg7<10; data_seg7++)
// 利用循环语句产生显示数据
{
seg7_1ms(data_seg7); // 调用驱动 1 位数码管的同步串行数据接口驱动函数
delay_1s( ); // 调用 1s 延迟函数
}
}
}
void seg7_1ms(unsigned char seg7_data) // 驱动 1 位数码管的同步串行数据接口驱动函数
// P1.7 数据管脚,P1.6 同步时钟管脚
{
unsigned char code_seg7; // 声明显示代码变量
code_seg7= decoder_seg7 [seg7_data]; // 数据译码
// 同步串行接口初始化
P1OUT&=~BIT6; // P1.6 输出低电平
P1OUT&=~BIT7; // P1.7 输出低电平
// 逐位输出 1 个字节的 8 个数据位
// 输出第 1 位数据(MSB)
// 产生数据信号
if(code_seg7&0x80)
{
P1OUT|=BIT7; // P1.7 输出高电平
}
else
{
P1OUT&=~BIT7; // P1.7 输出低电平
}
// 产生同步时钟信号
P1OUT|=BIT6; // P1.6 输出高电平
P1OUT&=~BIT6; // P1.6 输出低电平
// 输出第 2 位数据
// 产生数据信号
if(code_seg7&0x40)
{
P1OUT|=BIT7; // P1.7 输出高电平
}
else
{
P1OUT&=~BIT7; // P1.7 输出低电平
}
// 产生同步时钟信号
P1OUT|=BIT6; // P1.6 输出高电平
P1OUT&=~BIT6; // P1.6 输出低电平
// 输出第 3 位数据
// 产生数据信号
if(code_seg7&0x20)
{
P1OUT|=BIT7; // P1.7 输出高电平
}
else
{
P1OUT&=~BIT7; // P1.7 输出低电平
}
// 产生同步时钟信号
P1OUT|=BIT6; // P1.6 输出高电平
P1OUT&=~BIT6; // P1.6 输出低电平
// 输出第 4 位数据
// 产生数据信号
if(code_seg7&0x10)
{
P1OUT|=BIT7; // P1.7 输出高电平
}
else
{
P1OUT&=~BIT7; // P1.7 输出低电平
}
// 产生同步时钟信号
P1OUT|=BIT6; // P1.6 输出高电平
P1OUT&=~BIT6; // P1.6 输出低电平
// 输出第 5 位数据
// 产生数据信号
if(code_seg7&0x08)
{
P1OUT|=BIT7; // P1.7 输出高电平
}
else
{
P1OUT&=~BIT7; // P1.7 输出低电平
}
// 产生同步时钟信号
P1OUT|=BIT6; // P1.6 输出高电平
P1OUT&=~BIT6; // P1.6 输出低电平
// 输出第 6 位数据
// 产生数据信号
if(code_seg7&0x04)
{
P1OUT|=BIT7; // P1.7 输出高电平
}
else
{
P1OUT&=~BIT7; // P1.7 输出低电平
}
// 产生同步时钟信号
P1OUT|=BIT6; // P1.6 输出高电平
P1OUT&=~BIT6; // P1.6 输出低电平
// 输出第 7 位数据
// 产生数据信号
if(code_seg7&0x02)
{
P1OUT|=BIT7; // P1.7 输出高电平
}
else
{
P1OUT&=~BIT7; // P1.7 输出低电平
}
// 产生同步时钟信号
P1OUT|=BIT6; // P1.6 输出高电平
P1OUT&=~BIT6; // P1.6 输出低电平
// 输出第 8 位数据(LSB)
// 产生数据信号
if(code_seg7&0x01)
{
P1OUT|=BIT7; // P1.7 输出高电平
}
else
{
P1OUT&=~BIT7; // P1.7 输出低电平
}
// 产生同步时钟信号
P1OUT|=BIT6; // P1.6 输出高电平
P1OUT&=~BIT6; // P1.6 输出低电平
}
void delay_1s(void) // 1s 延迟函数
{
unsigned long data_delay; // 声明循环次数变量
// 利用循环语句实现时间延迟
for(data_delay=0; data_delay<126654; data_delay++)
{
}
}