背景
在嵌入式开发过程中,经常使用时、甚至设计时候,考虑成本等因素,需要外扩IO。这里就是使用STM8S003F3P6,这个芯片比较常用的,这个芯片封装很小,只有20个管脚的MCU,实际产品上用的非常多。
很多项目上都会使用,但是实际需求上,需要控制特别多灯,还有数码管,所以采用74hc164进行外扩IO的设计
原理图
部分原理图设计如下
软件设计
STM8S003F3P6的时钟配置,这里必须要提时钟配置,因为时钟关系到延时问题
所以,对于读者移植到其他MCU上比较关键
这里采用内部16M时钟,CPU选择1分频,就是主频时16Mhz
CLK_DeInit();//设置为默认值
CLK_HSICmd(ENABLE);//启用HSI
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);//HSI分频
CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);//CPU分频
初始化STM8S003F3P6
控制74HC164使用管脚,PA1/PD3
这里从原理图上可以看出来
GPIO_Init(GPIOA, (GPIO_Pin_TypeDef)(GPIO_PIN_1), GPIO_MODE_OUT_PP_LOW_SLOW);//PA1
GPIO_Init(GPIOD, (GPIO_Pin_TypeDef)(GPIO_PIN_4), GPIO_MODE_OUT_PP_LOW_SLOW);//PD4
74HC164控制头文件
这里主要是针对使用的宏定义,进行说明
STM8S003F3P6
控制74HC164使用管脚拉高、拉低宏定义
#define SHCP595_H {GPIO_WriteHigh(GPIOA, GPIO_PIN_1);}
#define SHCP595_L {GPIO_WriteLow(GPIOA, GPIO_PIN_1);}
#define DATA595_H {GPIO_WriteHigh(GPIOD, GPIO_PIN_4);}
#define DATA595_L {GPIO_WriteLow(GPIOD, GPIO_PIN_4);}
74hc164的控制逻辑
这里和手册里面描述的逻辑时一致的,这个函数是由74hc595改写过来,其实也类似74hc595
只是74HC595还多一个控制IO管脚
因为74hc595又锁存功能,可以先把数据放到缓存,然后通过STCP管脚的上升沿,将缓存数据生效。
这里讲多了,74hc164显然时序简单很多,可以参考如下代码
/**
* @brief 74HC164外扩IO
* @param
* @retval None.
**/
void HC164SendData(uint8_t OutData)
{
unsigned char i;
for (i = 0; i < 8; i++) //
{
SHCP595_L; //时钟线底
//HC164Dly(50);
if ((OutData & 0x80) == 0x80) //
{
DATA595_H; //
}
else
{
DATA595_L; //
}
OutData = OutData << 1; //
SHCP595_H; //
//HC164Dly(50);
}
//上升沿输出数据
///STCP595(0);
//HC164Dly(50);
///STCP595(1);
}
其他
74hc164的一些关键资料
当时钟信号(CP)从低电平变为高电平的时候将 DSA(B) 输入的一位数据输出到 Q0,当时钟第二次由低电平变为高电平的时候将 Q0 的数据移动到 Q1,新的数据依旧保存在 Q0。依此类推,每一个时钟周期中都有一个串行数据输入到 Q0,而其他的数据则不断往高位移动直到所有数据传输结束。如果不再有时钟周期输入,则这些数据将暂存在输出端。
由于 74HC164 不带锁存器功能,也就是说在每移一位数据都会实时反应在输出口上,这样会导致输出口有不必要的电平变化,虽然非常短暂但是,但是有些情况下这是不允许发生的,如果对时序逻辑有要求的话。