STM32驱动74HC165:GPIO模拟与硬件SPI实现输入扩展

发布时间:2026/10/21 14:00:13
STM32驱动74HC165:GPIO模拟与硬件SPI实现输入扩展 简介面向 STM32 开发者这份 74HC165 驱动资源以并行转串口移位寄存器为核心解决 GPIO 口不足时的多路信号采集与外设并联扩展问题适用于矩阵键盘、数码管显示、多通道数据采集等场景。压缩包只包含 2 个文件即 74HC165.c 源文件与 74HC165.h 头文件整体约 1KB结构十分精简。源文件实现了 GPIO 初始化、SH_CP 时钟控制、LE 使能切换、数据串行移位读取等底层逻辑头文件则提供对外接口声明方便直接嵌入 Keil/STM32 工程并按实际引脚修改配置。目前已有 734 人学习下载。通过这份代码使用者可快速完成 74HC165 的基础驱动搭建把有限的 MCU 引脚扩展出更多输入通道同时借助现成接口封装降低协议理解难度为后续矩阵按键扫描或多路采集等应用开发提供可复用的起点。1. 74HC165驱动STM32输入扩展的组件级解决方案做嵌入式项目时最常遇到的问题是IO口不够用尤其是按键、拨码开关这类开关量输入一个按键占一个脚几十个键下来MCU的引脚直接见底。74HC165就是专门干这个的8位并行输入、串行输出一片解决8个输入级联后一根时钟线、一根数据线就能拖几十路。我手头这份“74HC165驱动.rar”是针对STM32的里面既有GPIO模拟实现也有硬件SPI版本拿来对照移植就能用。接下来我把它的时序原理、驱动代码、常见坑和提速方法整个过一遍。适合那些正在做按键扫描、传感器状态读取或者想把手头输入扩展代码整理成库的人。2. 理解74HC165的核心时序并行加载与串行移位的配合2.1 74HC165的工作原理并行输入、串行输出的数据链路74HC165内部是一个8位移位寄存器外部有D0到D7八个并行输入引脚一个串行输出QH一个串行输入DS用于级联还有一个SH/LD移位/加载引脚和CLK时钟引脚。SH/LD是整个器件最关键的控制线把这个引脚拉低D0到D7的当前电平会被瞬间锁存到内部寄存器再把SH/LD拉高后续CLK引脚上的每一个脉冲都会让已锁存的数据向右移动一位并从QH引脚依次送出。也就是说读取操作分两步走先锁存再移位输出。关于先输出哪一位不同资料有不同的说法这也是驱动资源里最容易踩的第一个坑。按照主流数据手册比如某公司的74HC165型号QH对应D7路径在第一个CLK上升沿之后QH输出的是D7然后依次是D6、D5、D4、D3、D2、D1、D0。换句话说如果你把D7当作最高位那么读取到的第一个bit就是最高位。但有些芯片的丝印或者资源代码里把输出标成Q7并且内部移位方向是从Q7到Q0那么顺序会反过来。所以在移植这份“74HC165驱动.rar”之前第一步不是写代码而是拿起放大镜看芯片丝印确认是HC165N、HC165D还是别的后缀再去数据手册里翻图。顺序反了后面做数据拼接全都白搭。另外一个容易忽略的引脚是CLK INH时钟禁止。并不是所有驱动里都会用到它但逻辑上如果CLK INH为高时钟输入被忽略只有把它拉低CLK才能正常驱动。很多现成的驱动为了省引脚直接把CLK INH接到GND这个做法没问题。但如果你裁剪了引脚恰好把这个脚悬空那就会随机出现漏数、错数的问题。我一般会把它和GND焊在一起省事又稳定。理解这里的“锁存”和“移位”是读懂驱动代码的钥匙。锁存把并行的8个输入拍成一张“快照”移位则是按顺序把这张快照的每一位拿出来。因为这两步是分开的理论上可以在任意时刻锁存然后在空闲时慢慢移位读取这样读取动作就不会阻塞主循环太久。很多低功耗按键扫描方案就是这么做的定时器触发锁存随后在后台通过SPI读取不耽误主流程跑任务。2.2 STM32的SPI接口与74HC165的兼容性分析STM32的SPI外设天生适合接74HC165因为它本身就能当主机并产生时钟同时从MISO引脚读回数据。74HC165只有串行输出不需要主机给它写数据所以SPI的MOSI引脚可以空着或者悬空。连接方式非常简单STM32的SCK接74HC165的CLKSTM32的MISO接74HC165的QH再任意分配一个GPIO接到SH/LD用作锁存控制。但这里有个隐藏问题SPI的时钟极性和相位也就是CPOL和CPHA到底怎么配这直接决定了读取的数据是准确还是错位。74HC165的数据输出行为是在CLK上升沿内部移位寄存器动作QH电平发生改变在CLK下降沿时QH已经稳定。换句话说如果你想稳定采样眼睛应该盯在下降沿。对应到SPI的四种模式里模式1CPOL0CPHA1最匹配空闲时SCK为低第一个边沿是上升沿让74HC165移出下一位第二个边沿是下降沿此时STM32在SCK的下降沿读取MISO正好读到稳定的数据。不少驱动里默认写的是模式0也就是CPOL0CPHA0。为什么也能跑通因为低速情况下芯片输出建立时间很短STM32的采样可能在上升沿之后很晚才发生仍然落在稳定的窗口内。但一旦把SPI时钟频率拉到几MHz模式0就很容易飘出偶发错位。如果你接的是多片级联问题会更明显。我自己调试时有一个习惯先把SPI时钟设到1MHz用模式1测试确认无误后再逐步提速。这样能避免“代码看起来没问题但读数偶尔乱跳”的玄学问题。另外74HC165的时钟高电平宽度和建立保持时间是有最低要求的通常在几纳秒到几十纳秒级别。STM32的硬件SPI在低速模式下完全可以满足而软件模拟GPIO翻转虽然慢但可以通过延时兜底。理解这一点你就知道为什么资源包里通常会同时提供两套驱动一套GPIO模拟一套硬件SPI。前者的价值是“一定能用”后者的价值是“效率高”。2.3 驱动代码的总体框架GPIO模拟还是硬件SPI打开“74HC165驱动.rar”解压后一般能看到hc165.c源文件、hc165.h头文件以及一个示例工程。源码里的结构通常会把硬件引脚和软件逻辑分离。我见过不少现成驱动直接在头文件里写死引脚宏比如#define HC165_CLK_PIN GPIO_PIN_5 #define HC165_CLK_PORT GPIOA #define HC165_LD_PIN GPIO_PIN_6 #define HC165_LD_PORT GPIOA #define HC165_DATA_PIN GPIO_PIN_7 #define HC165_DATA_PORT GPIOA这种写法简单直接但换板子时要改头文件而且一旦项目里复用多个HC165实例就没法扩展。更稳妥的框架是用结构体管住引脚和配置typedef struct { GPIO_TypeDef *clk_gpio; uint16_t clk_pin; GPIO_TypeDef *ld_gpio; // SH/LD并行加载控制 uint16_t ld_pin; GPIO_TypeDef *dat_gpio; // QH串行输出读取 uint16_t dat_pin; uint8_t chip_num; // 级联片数1表示单芯片 } HC165_Handle_t;这个结构体把硬件依赖全部封装起来驱动函数只接受这个结构体指针。初始化时把GPIO的时钟打开、引脚模式配好再把结构体填好即可。这样你想把实例从PA切换到PB只需要改一处配置驱动层代码不用动。资源包里如果提供的是这类结构体驱动那它的扩展性就比宏定义版本好很多。选GPIO模拟还是硬件SPI取决于你的应用场景。如果输入通道只有八个、读取频率很低GPIO模拟完全够用而且不受引脚重映射限制想接哪个脚就接哪个脚。如果要做键盘矩阵扫描十几个键轮询读取甚至需要后台周期刷新那硬件SPI加DMA的收益会非常明显。下面的章节会分别给出这两种方式的具体代码和配置参数。3. 把74HC165驱动移植到STM32工程从解压到跑通3.1 资源包里常见的文件组成与目录结构解压“74HC165驱动.rar”之后通常会有两类东西一类是驱动代码文件另一类是示例工程。驱动代码核心文件一般不复杂就是hc165.c和hc165.h。示例工程则包含一个main.c里面演示了如何调用初始化函数和读取函数。有的资源包还会带一份数据手册的关键页截图或者一张接线图这些对快速跑通很有帮助。这里要提醒一点不要直接整个工程拿过来用。STM32的开发环境五花八门有人用标准库有人用HAL库有人用LL库还有人直接用寄存器。资源包里的示例工程很可能基于某一个固定型号的芯片而你的板子不一定相同。正确做法是只把hc165.c和hc165.h拿出来放到自己的工程里然后按照你自己的引脚定义重新注册一遍。这样能省去“把工程整体迁移过来的适配成本”。3.2 硬件连接电源、数据线、时钟线与片选先看接线。74HC165的工作电压一般是2V到6V和STM32的3.3V电平直接兼容不需要额外转换。VCC接3.3VGND共地。SH/LD接STM32任何一个空闲GPIO配置成推挽输出。CLK接SPI的SCK或者软件模拟时接一个GPIO输出。QH接SPI的MISO或者软件模拟时接一个GPIO输入。如果有多片级联把第一片的QH接到第二片的DS第二片的QH再接第三片的DS这样芯片之间串成一条链。注意第一片的DS接GND防止悬空引入噪声。有一个小细节74HC165的输出QH是推挽输出但它的DS输入在级联链上是有逻辑电平的不需要上拉。可如果你只用了单芯片DS悬空没关系但最好还是接到GND避免芯片内部输入级产生不确定状态。CLK INH同样接GND。这样把所有不用的输入引脚都固定在固定电平上读取结果才会稳定。下面是一个单芯片3.3V供电的典型接线表74HC165引脚接STM32/电源VCC3.3VGNDGNDSH/LD任意GPIO例PA0CLKGPIO或SPI SCK例PA5QHGPIO输入或SPI MISO例PA6DSGNDCLK INHGND使用软件模拟时PA5和PA6都是普通GPIO使用硬件SPI时需要查一下你所用的STM32型号中SCK和MISO的重映射关系不能凭感觉接。3.3 写一个最小驱动GPIO模拟时序的代码实现先从最保守的GPIO模拟开始。这份驱动的好处是不依赖SPI外设引脚随便选时序也能随时调整。核心代码就做两件事拉低SH/LD锁存数据然后循环8次每次都给CLK一个高脉冲并读取QH。下面是我整理过的单芯片GPIO模拟读取函数基于HAL库void HC165_Init(HC165_Handle_t *hc) { GPIO_InitTypeDef gpio {0}; // 开启GPIO时钟注意这里用__HAL_RCC_GPIOA_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE(); // CLK和LD配置为推挽输出 gpio.Mode GPIO_MODE_OUTPUT_PP; gpio.Pull GPIO_NOPULL; gpio.Speed GPIO_SPEED_FREQ_HIGH; gpio.Pin hc-clk_pin; HAL_GPIO_Init(hc-clk_gpio, gpio); gpio.Pin hc-ld_pin; HAL_GPIO_Init(hc-ld_gpio, gpio); // DATA配置为输入下拉可选通常外部已有上拉 gpio.Mode GPIO_MODE_INPUT; gpio.Pull GPIO_PULLDOWN; gpio.Pin hc-dat_pin; HAL_GPIO_Init(hc-dat_gpio, gpio); // 初始让CLK、LD都处于高电平 HAL_GPIO_WritePin(hc-clk_gpio, hc-clk_pin, GPIO_PIN_SET); HAL_GPIO_WritePin(hc-ld_gpio, hc-ld_pin, GPIO_PIN_SET); } uint8_t HC165_ReadByte(HC165_Handle_t *hc) { uint8_t data 0; // 拉低SH/LD锁存并行输入 HAL_GPIO_WritePin(hc-ld_gpio, hc-ld_pin, GPIO_PIN_RESET); // 延时至少满足脉宽要求这里用几个空循环代替 for (volatile int i 0; i 10; i); // 拉高SH/LD开始移位 HAL_GPIO_WritePin(hc-ld_gpio, hc-ld_pin, GPIO_PIN_SET); for (volatile int i 0; i 10; i); // 循环8次先D7后D0 for (int i 0; i 8; i) { // CLK拉高74HC165在这条上升沿后移出下一位 HAL_GPIO_WritePin(hc-clk_gpio, hc-clk_pin, GPIO_PIN_SET); // 等待数据稳定根据主频调整延时 for (volatile int j 0; j 5; j); // 读取QH放在高电平中间段 if (HAL_GPIO_ReadPin(hc-dat_gpio, hc-dat_pin) GPIO_PIN_SET) { data | (0x80 i); // 按D7到D0顺序填充 } // CLK拉低准备下一个上升沿 HAL_GPIO_WritePin(hc-clk_gpio, hc-clk_pin, GPIO_PIN_RESET); for (volatile int j 0; j 5; j); } return data; }这段代码的逻辑顺序是先锁存再移位读取。读取时数据位从高位开始。data | (0x80 i)表示第0次读到D7时放在bit7位置第7次读到D0时放在bit0位置。如果你想把D0放在bit7只需要改成data | (0x01 i)。这是资源包里非常常见的位序调整点。延时参数需要根据STM32主频调整。上面代码里的循环次数在72MHz下大概能产生几百纳秒的延时足够74HC165稳定输出。如果你跑在168MHz或者更低主频可以把循环次数改成变量或者用delay_us()函数。一个经验法则是CLK高电平持续时间至少是数据手册要求的时钟脉冲宽度乘以10确保余量足够。3.4 参数配置时钟频率、采样点与级联数量GPIO模拟方式下没有真正意义上的时钟频率但CLK翻转速度决定了读取一次的时间。这里有两个参数值得关注一个是采样点一个是延时值。采样点必须在CLK拉高之后、数据稳定之后不能在上升沿瞬间去读否则极容易读到上一个bit的旧值。所以代码里CLK拉高后加了几条空指令。如果你发现读取的第一个bit总是丢多半是采样点太早。级联时只需要把8次循环扩展成8 * hc-chip_num次并且用一个数组存储数据。比如两片级联循环16次第一片的数据会先出现在QH链上但最后读入的字节属于第一片还是第二片取决于你的级联接法。多数情况下数据是先从离STM32最远的那片开始送进链所以数组下标小的元素反而对应后一片。这里没有标准答案必须以实测结果为准。我一般会写一个自测函数把所有并行输入引脚接成固定的0xAA和0x55模式然后读回来和预期值比对。如果结果正好翻转说明位序反了如果数据整体跑到了临近的字节说明级联顺序理解反了。这个自测方法百试百灵也建议你把它留在工程里方便后续排障。4. 避坑与常见问题74HC165驱动调试中的五个教训4.1 现象读取的按键状态整体顺序颠倒按下第一个按键读出来却是第8个按键的状态或者反过来。原因通常是位序处理错了。很多示例代码默认先输出D0但74HC165硬件特性是先输出D7。解决方法是把填充逻辑从data | (0x80 i)改成data | (0x01 i)或者交换引脚连接顺序。更通用的办法是查看数据手册里时序图的第一个时钟脉冲对应哪个输入引脚。从那以后我拿到任何移位寄存器芯片第一件事就是看时序图不猜。4.2 现象有些输入引脚悬空读出来随机跳变当有的开关没有接上拉或下拉电阻时74HC165的输入电平会浮在空中读出来是0还是1完全看当天运气。原因就是CMOS输入悬空。解决方法是给所有并行输入引脚加外部上拉电阻或者至少把不用的输入引脚接到GND/VCC。在某些键盘矩阵场景里按键本身会提供通路但空闲状态需要上拉电阻才能保证逻辑稳定。还有一个软件上的兜底办法如果连续两次读取结果不一致说明硬件上确实有浮动赶紧查硬件。4.3 现象用GPIO模拟读数据首位偶尔丢失代码看起来完全正确但十次里有两次第一个bit读成了0把按键状态吃掉。原因多半是采样点离上升沿太近QH电平还没有稳定。解决方法是把CLK拉高后的延时调大比如从5个空循环改成20个空循环。另外注意CLK拉高之后不要立即调用HAL_GPIO_ReadPin因为函数调用本身也有开销可能正好卡在电平转换的毛刺上。稳妥的做法是先让CLK高电平保持一小段时间再读数据。4.4 现象多片级联时数据字节错乱两片74HC165级联读回来的两个字节和你预期的输入顺序对不上。原因有两类一是级联的DS引脚接错QH没有送到下一片DS二是软件里循环次数或者数组填充顺序搞反。解决方法是先写入一个固定模式硬件验证比如第一片输入0x0F第二片输入0xF0看读出的两个字节是否是0x0F和0xF0。据此调整循环方向。实际经验中级联数据错乱90%是软件数组排列问题不是硬件接线问题。4.5 现象使用硬件SPI时读取结果受到其他SPI设备干扰当74HC165和别的SPI设备挂在同一条总线上时SCK和MISO可能被其它设备的事务打断。原因是没有给每个设备分配独立的片选。74HC165没有片选引脚它的SH/LD只能当锁存控制不能完全隔离总线。解决方法是如果系统中有人机交互屏、Flash等SPI设备尽量让74HC165独占一个SPI外设或者用软件模拟方式读取。非要共用一个SPI时必须在其它设备传输期间避免操作74HC165并且使用互斥标志保护。我在这上面翻过车后来直接把按键读取独立到软件模拟再不给主SPI添乱。5. 使用硬件SPI提升读取效率寄存器配置与DMA5.1 为什么用硬件SPICPU占用率对比GPIO模拟方式虽然简单但真正跑起来效率不高。假设你要读8片74HC165也就是64个输入每个输入至少需要一次CLK翻转、一次数据读取和一次延时累计下来要上百次GPIO操作。主频72MHz下一次GPIO翻转加读取可能耗时几百纳秒到一两微秒全部读完需要接近毫秒级。这在按键扫描里不算慢但如果你做的是传感器数据采集每秒钟要刷新几百次CPU占用率就会变得难看。硬件SPI的方式则完全不同。SPI外设自动产生8个时钟脉冲同时把MISO上的数据移位进接收寄存器。CPU只需要启动一次传输然后等SPI的RXNE标志位即可。如果配合DMA连等待都可以省掉。实测下来读取8个字节的时间只有GPIO模拟的十分之一左右CPU占用几乎可以忽略。对于需要频繁读取的工业输入检测场景硬件SPI是必然选择。5.2 SPICLK极性相位配置详解使用硬件SPI驱动74HC165最重要的就是配置CPOL和CPHA。根据前面的时序分析推荐使用SPI模式1即CPOL0、CPHA1。在STM32的HAL库里配置代码可以这样写SPI_HandleTypeDef hspi; hspi.Instance SPI1; hspi.Init.Mode SPI_MODE_MASTER; hspi.Init.Direction SPI_DIRECTION_2LINES; hspi.Init.DataSize SPI_DATASIZE_8BIT; hspi.Init.CLKPolarity SPI_POLARITY_LOW; // CPOL0 hspi.Init.CLKPhase SPI_PHASE_2EDGE; // CPHA1 hspi.Init.NSS SPI_NSS_SOFT; hspi.Init.BaudRatePrescaler SPI_BAUDRATEPRESCALER_16; hspi.Init.FirstBit SPI_FIRSTBIT_MSB; HAL_SPI_Init(hspi);这里SPI_POLARITY_LOW表示空闲时钟为低SPI_PHASE_2EDGE表示数据在第二个时钟边沿采样。为什么要选第二个边沿因为第一个边沿是上升沿74HC165此时正在改变QH输出数据还没稳定采样点放在下降沿正好。如果你用模式0也就是SPI_PHASE_1EDGE在低速下可能正常但我不推荐。关于波特率预分频74HC165本身可以跑很高但考虑到PCB走线、上下拉电阻和STM32内部GPIO速度建议先从SPI_BAUDRATEPRESCALER_16开始调。如果系统时钟72MHz预分频16后SPI时钟4.5MHz配合模式1读取非常稳。等验证逻辑正确后再尝试预分频8或4提高吞吐率。一旦出现偶发错误马上把频率降回来别硬抗。5.3 用DMA连续采集多片74HC165要发挥硬件SPI的优势一定要配合DMA。DMA模式下的读取流程是先拉低SH/LD锁存再拉高SH/LD然后启动DMA接收。由于SPI的接收和发送是同时发生的你需要同时提供一个发送缓冲里面的数据无所谓通常填0x00。DMA会把SPI接收寄存器里的数据连续搬到一个数组中读取完成后触发中断。以下是一段基于HAL库的DMA读取代码uint8_t spi_tx_buf[8] {0}; uint8_t spi_rx_buf[8]; void HC165_ReadDMA(HC165_Handle_t *hc) { // 锁存并行数据 HAL_GPIO_WritePin(hc-ld_gpio, hc-ld_pin, GPIO_PIN_RESET); for (volatile int i 0; i 10; i); HAL_GPIO_WritePin(hc-ld_gpio, hc-ld_pin, GPIO_PIN_SET); // 启动SPI DMA接收长度等于芯片数量 HAL_SPI_Receive_DMA(hspi, spi_rx_buf, hc-chip_num); // 如果不想用DMA传输完成中断也可以在这里等待 // 等待DMA传输完成这在中断里做更合适 // 通过回调函数里读取spi_rx_buf得到最终结果 }这段代码里面HAL_SPI_Receive_DMA会非阻塞地启动传输传输完成后会在HAL_SPI_RxCpltCallback里回调。你需要在中断服务函数或者主循环里处理这些字节。注意DMA传输期间不能再去操作SPI否则会打乱时序。另外拉低SH/LD到启动SPI之间要有足够延时确保74HC165内部已经完成锁存。这个延时用几个空循环即可不要用HAL_Delay因为HAL_Delay基于SysTick在中断里调用容易出问题。5.4 与软件模拟的取舍硬件SPI加DMA的性能优势明显但代价是引脚固定、配置复杂、调试难度更高。实际工程中我的选择逻辑是这样的如果只需要读取8到16个输入且读取频率很低直接用GPIO模拟最省心如果需要读取32路以上或者系统里还有其它SPI设备那就单独给74HC165开一个SPI用DMA方式读取。还有一种折中方案用硬件SPI但不启用DMA在中断里单字节读取。这能降低一半CPU占用又不需要处理DMA回调适合中等规模场景。资源包里如果同时提供两套驱动可以看作是一个很好的对照实验先用GPIO模拟跑通硬件再切换到硬件SPI对比读取结果是否一致。这个对比过程能帮你验证SPI模式的配置是否正确也能帮你排除“接错引脚”这种低级问题。6. 进阶把驱动封装成库支持任意数量级联与一键读取6.1 设计一个不依赖具体硬件的抽象层当你在两三个项目里重复使用74HC165驱动之后就会发现硬编码引脚很痛苦。更好的做法是把驱动分成两层底层管GPIO或SPI操作上层管数据解析。底层通过结构体传入引脚上层通过函数指针调用底层接口。这样即使从STM32换到其它MCU只需要改底层实现上层扫描逻辑完全不用动。我写过一个简化版本在结构体里挂函数指针typedef struct { void (*init)(void); uint8_t (*read)(uint8_t chip_index); void (*set_ld)(uint8_t level); } HC165_LowLevel_t;上层代码只调用这些指针不关心它们到底是操作GPIO还是SPI。测试时还能把指针指向模拟函数方便在PC上做单元验证。6.2 使用枚举与结构体管理通道状态74HC165读取回来的数据是一堆位直接读字节数组可读性很差。我一般会把每个输入映射到一个枚举或联合体里方便业务代码使用。比如typedef union { uint8_t raw; struct { uint8_t key0 : 1; uint8_t key1 : 1; uint8_t key2 : 1; uint8_t key3 : 1; uint8_t key4 : 1; uint8_t key5 : 1; uint8_t key6 : 1; uint8_t key7 : 1; } bits; } HC165Input_t;这样读取完原始字节后只需要通过input.bits.key3就能判断第3路按键状态代码可读性提升很多。同时在封装时要注意位域顺序它和芯片输出顺序有对应关系最好配合注释说明。6.3 验证方法用逻辑分析仪对比波形封装完成后怎样才算彻底跑通我通常会用逻辑分析仪同时抓CLK、SH/LD和QH三个信号。观察锁存脉冲宽度是否足够CLK高电平时间是否满足芯片要求QH数据是否在每个上升沿之后发生预期翻转。如果你有支持SPI解码的逻辑分析仪直接把QH当作MISO、CLK当作SCK解码出的字节应该等于你期望的按键状态。我个人的习惯是每次改完驱动代码都强制自己走一遍“硬件自测模式”把所有输入引脚接到固定高/低电平组合读回来和预期比对。这个自测函数几十行但能省下无数排查时间。从那以后不管是用GPIO模拟还是硬件SPI我都会在工程里保留这个自测入口保证任何一块板子拿过来十分钟内就能判定是代码问题还是硬件问题。希望这篇文章能帮你把74HC165驱动用得更顺手。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询