一. 74HC595芯片介绍
74HC595是串口转并口芯片,可输出三种状态:高电平、低电平和高组态。
一片74HC595芯片可实现3根口线扩展为8根口线.也可采用多片74HC595进行级联的方式扩展输出口线。
Q0~Q7: 并行数据数据输出端;
GND: 接地引脚;
Q7S: 串行数据输出(多芯片级联时使用);
MR: 复位引脚,当引脚接低电平时芯片内部数据存储寄存器数据清零复位.如不使用一般接高电平;
SHCP: 移位寄存器的时钟输入,当接收到上升沿时移位寄存器内部数据整体后移;
STCP: 数据存储寄存器时钟输入,当检测到上升沿时使能数据存储寄存器,将芯片接收到的数据输出到Q0~Q7 ,Q7S引脚.可以将其理解为锁存信号,当数据发送给芯片完成后对该引脚发送上升沿;
OE: 输出使能引脚,为高电平时芯片输出引脚为高组态,当为低电平时芯片输出引脚为高(低)电平.该引脚可用于同时控制并行输出引脚的电平,如控制LED闪烁等.当不使用该功能时通常接低电平;
DS: 串行数据输入端
VCC: 电源引脚
从功能框图中可以看出74HC595含有一个移位寄存器,一个存储寄存器和一个三态输出控制器。
在使用74HC595设计电路时应注意不同厂家生产的芯片对时钟最高频率和高电平保持时间范围都有不同要求.应查看对应厂家的芯片Data Sheet.本例程中使用的是Nexperia (NXP)所生产的74HCT595。
二. 74HC595硬件设计与74HC595驱动程序
1.单芯片工作模式
/** ****************************************************************************** * @file LED.c * @author Ryan Zhao * @version V1.0.0 * @date 2017-05-03 * @brief 用于通过驱动芯片74HC595来控制LED. ****************************************************************************** * @attention * 注意CPU引脚的频率应在74HC595正常工作所允许的范围. ****************************************************************************** **/ /** * @brief 74HC595 的引脚初始化. * @param None. * @retval None. */ void LED595Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE); //如果74HC595的驱动引脚为JTAG,则将JTAG引脚禁用并配置为通用GPIO引脚. //如果驱动引脚为通用GPIO则需要注释掉以下内容 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//禁止JTAG功能,保留SWD GPIO_InitStructure.GPIO_Pin = LED595_DATA_PIN | LED595_LATCH_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_ResetBits(GPIOB,LED595_DATA_PIN | LED595_LATCH_PIN); //Data Pin GPIO_InitStructure.GPIO_Pin = LED595_DATA_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(LED595_DATA_PORT, &GPIO_InitStructure); //Clk Pin GPIO_InitStructure.GPIO_Pin = LED595_CLK_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(LED595_CLK_PORT, &GPIO_InitStructure); //Latch Pin GPIO_InitStructure.GPIO_Pin = LED595_LATCH_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(LED595_LATCH_PORT, &GPIO_InitStructure); } /** * @brief 将输入的数据输出到74HC595的引脚. * @param Input 1 byte data. * @retval None. **/ void LED595SendData(unsigned char OutData) { unsigned char i; //发送数据时做循环使用临时变量 for(i=0; i<8; i++) //将8位数据按位发送,先发送高字节后发送低字节 { LED595_CLK_RESET;//时钟线低电平 if( (OutData & 0x8000) == 0x8000)//判断数据高低位 { LED595_DATA_SET; //数据线高电平 } else { LED595_DATA_RESET; //数据线低电平 } OutData = OutData << 1; //数据左移1位 LED595_CLK_SET; //时钟线高电平 } //上升沿输出数据 LED595_LATCH_RESET; LED595_LATCH_SET; }
/** ****************************************************************************** * @file LED595.h * @author Ryan Zhao * @version V1.0.0 * @date 2017-05-03 * @brief 用于通过驱动芯片74HC595来控制LED. ****************************************************************************** * @attention * 注意CPU引脚的切换速度应在74HC595正常工作所允许的范围. ****************************************************************************** **/ //74HC595口线定义宏定义.当驱动74HC595引脚改变时,只需更改底层引脚宏定义即可 #define LED595_DATA_PORT GPIOB #define LED595_DATA_PIN GPIO_Pin_3 #define LED595_CLK_PORT GPIOB #define LED595_CLK_PIN GPIO_Pin_5 #define LED595_LATCH_PORT GPIOB #define LED595_LATCH_PIN GPIO_Pin_4 //74HC595口线高低电平宏定义 #define LED595_DATA_SET GPIO_SetBits(LED595A_DATA_PORT,LED595A_DATA_PIN) #define LED595_DATA_RESET GPIO_ResetBits(LED595A_DATA_PORT,LED595A_DATA_PIN) #define LED595_CLK_SET GPIO_SetBits(LED595A_CLK_PORT,LED595A_CLK_PIN) #define LED595_CLK_RESET GPIO_ResetBits(LED595A_CLK_PORT,LED595A_CLK_PIN) #define LED595_LATCH_SET GPIO_SetBits(LED595A_LATCH_PORT,LED595A_LATCH_PIN) #define LED595_LATCH_RESET GPIO_ResetBits(LED595A_LATCH_PORT,LED595A_LATCH_PIN)
函数使用
LED595SendData(0xFF); //74HC595输出端全部为高电平,LED全部熄灭 LED595SendData(0x00); //74HC595输出端全部为低电平,LED全部点亮
2.级联工作模式
/** ****************************************************************************** * @file LED.c * @author Ryan Zhao * @version V1.1.0 * @date 2017-06-05 * @brief 用于通过驱动芯片74HC595来控制LED. ****************************************************************************** * @attention * * 注意CPU引脚的切换速度应在74HC595正常工作所允许的范围. * ****************************************************************************** **/ /** * @brief 74HC595 的引脚初始化. * @param None. * @retval None. */ void LED595Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE); //Data Pin GPIO_InitStructure.GPIO_Pin = LED595_DATA_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(LED595_DATA_PORT, &GPIO_InitStructure); //Clk Pin GPIO_InitStructure.GPIO_Pin = LED595_CLK_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(LED595_CLK_PORT, &GPIO_InitStructure); //Latch Pin GPIO_InitStructure.GPIO_Pin = LED595_LATCH_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(LED595_LATCH_PORT, &GPIO_InitStructure); } /** * @brief LED显示函数. * @param 要显示的数据. * @retval None. **/ void LED595SendData(unsigned int OutData) { unsigned char i; //发送数据时做循环使用临时变量 for (i = 0; i < 16; i++) //将16位数据按位发送 { LED595_CLK_RESET; //时钟线低电平 if ((OutData & 0x8000) == 0x8000) //判断数据高低位 { LED595_DATA_SET; //发送数据高位 } else { LED595_DATA_RESET; //发送数据低位 } OutData = OutData << 1; //数据左移1位 LED595_CLK_SET; //时钟线高电平 } //上升沿输出数据 LED595_LATCH_RESET; LED595_LATCH_SET; }
/** ****************************************************************************** * @file LED595.h * @author Ryan Zhao * @version V1.1.0 * @date 2017-05-03 * @brief 用于通过驱动芯片74HC595来控制LED. ****************************************************************************** * @attention * * 注意CPU引脚的切换速度应在74HC595正常工作所允许的范围. * ****************************************************************************** **/ /**********************物理层定义******************************/ //74HC595口线定义宏定义.当驱动74HC595引脚改变时,只需更改底层引脚宏定义即可 #define LED595_DATA_PORT GPIOC #define LED595_DATA_PIN GPIO_Pin_5 #define LED595_CLK_PORT GPIOB #define LED595_CLK_PIN GPIO_Pin_0 #define LED595_LATCH_PORT GPIOB #define LED595_LATCH_PIN GPIO_Pin_1 //74HC595口线高低电平宏定义 #define LED595_DATA_SET GPIO_SetBits(LED595_DATA_PORT,LED595_DATA_PIN) #define LED595_DATA_RESET GPIO_ResetBits(LED595_DATA_PORT,LED595_DATA_PIN) #define LED595_CLK_SET GPIO_SetBits(LED595_CLK_PORT,LED595_CLK_PIN) #define LED595_CLK_RESET GPIO_ResetBits(LED595_CLK_PORT,LED595_CLK_PIN) #define LED595_LATCH_SET GPIO_SetBits(LED595_LATCH_PORT,LED595_LATCH_PIN) #define LED595_LATCH_RESET GPIO_ResetBits(LED595_LATCH_PORT,LED595_LATCH_PIN) #define LED595_DATA_PORT GPIOC #define LED595_DATA_PIN GPIO_Pin_5 #define LED595_CLK_PORT GPIOB #define LED595_CLK_PIN GPIO_Pin_0 #define LED595_LATCH_PORT GPIOB #define LED595_LATCH_PIN GPIO_Pin_1 //74HC595口线高低电平宏定义 #define LED595_DATA_SET GPIO_SetBits(LED595_DATA_PORT,LED595_DATA_PIN) #define LED595_DATA_RESET GPIO_ResetBits(LED595_DATA_PORT,LED595_DATA_PIN) #define LED595_CLK_SET GPIO_SetBits(LED595_CLK_PORT,LED595_CLK_PIN) #define LED595_CLK_RESET GPIO_ResetBits(LED595_CLK_PORT,LED595_CLK_PIN) #define LED595_LATCH_SET GPIO_SetBits(LED595_LATCH_PORT,LED595_LATCH_PIN) #define LED595_LATCH_RESET GPIO_ResetBits(LED595_LATCH_PORT,LED595_LATCH_PIN)
函数使用
LED595SendData(0xFFFF); //74HC595输出端全部为高电平,LED全部熄灭 LED595SendData(0x0000);//74HC595输出端全部为低电平,LED全部点亮