74HC595D介绍与实现(C语言与verilog实现)

74HC595D介绍与实现(C语言与verilog实现)1 特性 8 位串行输入 8 位可串行或并行输出 具有 3 种状态输出的存储寄存器 具有复位功能的移位寄存器 具有串行输入 DS 和串行输出 Q7S 来级联的功能 移位寄存器和存储寄存器的时钟可分开控制 2 引脚说明 引脚名 引脚号 说明 Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 15 1 2 3 4 5 6

大家好,我是讯享网,很高兴认识大家。

1.特性

  • 8位串行输入
  • 8位可串行或并行输出
  • 具有3种状态输出的存储寄存器
  • 具有复位功能的移位寄存器
  • 具有串行输入(DS)和串行输出(Q7S)来级联的功能。
  • 移位寄存器和存储寄存器的时钟可分开控制。

2.引脚说明


讯享网

引脚名 引脚号 说明
Q0、Q1、Q2、Q3、Q4、Q5、Q6、Q7 15,1,2,3,4,5,6,7 并行数据输出
Q7S 9 串行数据输出
MR 10 主复位引脚,为0时复位移位寄存器
SHCP 11 移位寄存器时钟输入,上升沿时DS上的数据会移入移位寄存器
STCP 12 存储寄存器时钟输入,上升沿时移位寄存器的数据传输到存储寄存器
OE 13 输出使能,为0时,存储器中的数据并行输出到Q0-Q7引脚;为1时,输出为高阻态
DS 14 串行数据输入

3.逻辑与时序操作

3.1 逻辑操作

由上图可看出,8位以为寄存由DS、SHCP、MR这三个引脚控制,8位存储寄存器有STCP引脚控制,而输出由OE引脚控制。Q7S引脚控制级联。数据先经过移位寄存器,再锁存到存储寄存器中,最后在OE引脚为低时数据并行输出。

3.2 时序操作

由3.1的逻辑图和上图结合可看出:

  • 驱动74HC595主要控制SHCP、DS、STCP、MR、OE这5个引脚,可把MR引脚拉高不复位移位寄存器、OE引脚拉低一直输出,这样实际控制的引脚只有3个。
  • DS引脚上的数据在SHCP处于上升沿时写入到移位寄存器;
  • DS引脚先送高位再送低位,如写入二进制数据,则最先写入1到Q1上,再写入0,则Q0上的1被挤到Q1,Q0上的数据变为0,以此类推。最后移位寄存器上Q7-Q0的数据为;
  • MR引脚为低时清空移位寄存器中的数据;

  • 当写入的数据超过8位时,最先写入的数据会经过Q7S引脚输出,如写入数据,此时再写入一位数据0,则Q7上的数据1会被挤到Q7S上,Q6的数据挤到Q7上,以此类推,Q0补上新写入的数据0,此时Q7~Q0的数据为0;
  • 当STCP引脚处于上升沿时,移位寄存器上的8位数据将一次性锁存到存储寄存器中;
  • OE引脚为低电平时,存储寄存器上的数据会输出到并出输出引脚(Q0-Q7)上。为高电平时,并行输出引脚(Q0-Q7)则为高阻态

img

4.级联

使用级联功能时,所有的74HC595D的第10、11、12引脚全部连接到主控芯片的引脚上,U27的第9引脚连接到U26的第14引脚上,形成级联功能;13引脚接地,使得595芯片一直输出。

级联的数据由U27的14引脚输入,当写入的数据超过8位时,最先写入的数据会通过第9引脚输出到U26的14引脚,写入到U26的移位寄存器中。

img

5.C语言实现

5.1 引脚初始化

主控芯片:STM32F103RCT6

使用到的引脚PB4->STCP、PB5->MR、PB6->SHCP、PB7->DS,全部配置成通用推挽输出,需要注意的是由于使用到PB4引脚,PB4默认启用时不是普通引脚,是JTAG的复用功能-NJTRST,因此需要关闭JTAG-DP,启用SW-DP需要增加以下两行代码

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); void HC595_init() { GPIO_InitTypeDef GPIO_InitStructure;   RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); ​   GPIO_InitStructure.GPIO_Pin =GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //通用推挽输出   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   GPIO_Init(GPIOB, &GPIO_InitStructure);   GPIO_ResetBits(GPIOB,GPIO_Pin_4|GPIO_Pin_6|GPIO_Pin_7);//拉低   GPIO_SetBits(GPIOB,GPIO_Pin_5);//MR一直为高,不复位移位寄存器 } ​

讯享网

5.2 发送数据

讯享网/* *发送数据,没有级联时,len设为1,有级联时,len为级联数 */ ​ void HC595_send_data(u8 *data,u16 len) { u8 i,j; u8 temp; for(i = 0;i < len;i++) { temp = data[i]; for(j = 0;j < 8;j++) { if(temp & 0x80)//先发送高位 GPIO_SetBits(GPIOB,GPIO_Pin_7); else GPIO_ResetBits(GPIOB,GPIO_Pin_7); GPIO_ResetBits(GPIOB,GPIO_Pin_6); delay(2); GPIO_SetBits(GPIOB,GPIO_Pin_6);//SHCP为上升沿时写入数据 delay(2); temp <<= 1; } } GPIO_ResetBits(GPIOB,GPIO_Pin_4); delay(2); GPIO_SetBits(GPIOB,GPIO_Pin_4);//STCP为上升沿时移位寄存器上的数据锁存到存储寄存器上 delay(2); }

5.3 main函数

int main() { u8 data[5]={0x88,0x88,0x88,0x88,0x88}; HC595_init(); HC595_send_data(data,5);//Q4和Q7为1,其余皆为0 while(1) { ; } }

6.Verilog实现

主控芯片:EP4CE10F17C8

讯享网module hc595d_drive( input clk, input rst_n, //用户接口 // input wire hc595d_wr_en,//写入使能标志 // input wire [31:0] wr_data, //待写入的数据 // input wire [2:0] wr_data_len;//待写入数据的字节长度 output reg hc595d_stcp, output wire hc595d_mr, output reg hc595d_shcp, output reg hc595d_ds, ); //localparam define localparam S0 = 4'd0; localparam S1 = 4'd1; localparam S2 = 4'd2; localparam S3 = 4'd3; localparam S4 = 4'd4; localparam S5 = 4'd5; wire [31:0] wr_data; //待写入的数据 wire [2:0] wr_data_len; //待写入数据的字节长度 reg hc595d_wr_en; //写入使能标志 reg wr_data_flag; //开始写入数据标志 reg [2:0] wr_bitdata_cnt/*synthesis noprune*/; //计数写入数据的位数 reg [3:0] wr_bytedata_cnt/*synthesis noprune*/; //计数写入数据的字节数 reg [3:0] cur_s;//当前状态 reg [3:0] next_s;//下一次状态 reg [7:0] byte_num; //统计写入的位数 reg [31:0] count_num;//计数器 //上升沿接口 wire en_flag; reg en_d0; reg en_d1; / main code / //hc595d_mr拉高,不复位移位寄存器 assign hc595d_mr = 1; //写入的数据 assign wr_data = {8'h11,8'h11,8'h11,8'h11}; //写入的字节数 assign wr_data_len = 3'd4; //捕获hc595d_wr_en上升沿,可以写入数据 assign en_flag = (~en_d1) & en_d0; //对写使能信号hc595d_wr_en延迟两个时钟周期 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin en_d0 <= 1'b0; en_d1 <= 1'b0; end else begin en_d0 <= hc595d_wr_en; en_d1 <= en_d0; end end //计时 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin count_num <= 0; hc595d_wr_en <= 0; end else begin if(count_num == 32'hffff) begin count_num <= 0; hc595d_wr_en <= 1; end else count_num <= count_num + 1; end end //写入标志位控制 always @(posedge clk or negedge rst_n) begin if(!rst_n) begin wr_data_flag <= 0; end else begin if(en_flag) begin //接收数据,开始写入数据标志位置1 wr_data_flag <= 1; end else if(wr_bitdata_cnt == wr_data_len) begin //写完了 wr_data_flag <= 0; end else begin wr_data_flag <= wr_data_flag; end end end //三段式状态机 //状态转移 always @(posedge clk or negedge rst_n) begin if(!rst_n) begin cur_s <= 0; end else begin cur_s <= next_s; end end //转移条件 always @(*) begin if(wr_data_flag) begin case (cur_s) S0: next_s = S1; S1: next_s = S2; S2: next_s = S3; S3: begin if(wr_bytedata_cnt == 4'd8) next_s = S4; else next_s = S0; end S4: begin if(wr_bitdata_cnt == wr_data_len) next_s = S5; else next_s = S0; end S5: begin next_s = S0; end default: next_s = S0; endcase end else begin next_s = S0; end end //状态输出 写入wr_data_len个字节的数据 always @(posedge clk or negedge rst_n) begin if(!rst_n) begin wr_bitdata_cnt <= 3'd0; wr_bytedata_cnt <= 4'd0; hc595d_stcp <= 0; hc595d_shcp <= 1'd0; hc595d_ds <= 0; byte_num <= 0; end else begin case(cur_s) S0:begin hc595d_stcp <= 1'd0; hc595d_shcp <= 1'd0; end S1:begin hc595d_ds <= wr_data[4'd31 - byte_num];//输出高位数据 end S2:begin hc595d_shcp <= 1'd1; //上升沿,数据写入移位寄存器 wr_bytedata_cnt <= wr_bytedata_cnt + 1;//位数+1 byte_num <= byte_num + 1;//位数+1 end S3:begin if(wr_bitdata_cnt== 4'd8)begin //8位一个字节 wr_bitdata_cnt<= 0; wr_bytedata_cnt<= wr_bytedata_cnt+ 1;//字节数+1 end end S4:begin if(wr_bytedata_cnt== wr_data_len)begin //写完了 wr_bytedata_cnt= 3'd0; hc595d_stcp <= 1'd1;//上升沿,移位寄存器所存在存储寄存器并输出 byte_num <= 0; end end S5:begin wr_bitdata_cnt <= 3'd0; wr_bytedata_cnt <= 4'd0; hc595d_stcp <= 0; hc595d_shcp <= 1'd0; hc595d_ds <= 0; byte_num <= 0; end default:begin wr_bitdata_cnt <= 3'd0; wr_bytedata_cnt <= 4'd0; hc595d_stcp <= 0; hc595d_shcp <= 1'd0; hc595d_ds <= 0; byte_num <= 0; end endcase end end endmodule

        上面的代码可以上电烧录之后就直接将数据写入到hc595d,上电后count_num计数到32‘hffff后,使能hc595d_wr_en,检测到hc595d_wr_en上升沿,就开始向hc595d写入wr_data_len个字节的数据,写入的数据是根据wr_data中的数据而定,高位先出,上面代码实现的效果是Q0和Q4为1,其余皆为0;若想更改写入的字节数或写入的数据,可以更改wr_data_len和wr_data中的数据。

        若要用外部接口去控制写入的数据、写入字节数和使能,可以将用户接口打开,同时将下面三条语句注释掉。

wire [31:0] wr_data; //待写入的数据 wire [2:0] wr_data_len; //待写入数据的字节长度 reg hc595d_wr_en; //写入使能标志

小讯
上一篇 2025-02-27 23:27
下一篇 2025-03-01 13:18

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/49990.html