学好单片机必须了解的10个电路,一个都不能放过

本文深入探讨单片机及其周边电路的设计细节,包括上拉电阻选择、LED串联电阻计算、端口扩展、滤波电容使用、三极管功能、数码管驱动、电流电压驱动、上下拉电阻原理、晶振与复位电路配置,以及按键抖动消除等关键主题。

一、单片机上拉电阻的选择

学好单片机必须了解的10个电路,一个都不能放过

大家可以看到复位电路中电阻R1=10k时RST是高电平 ,而当R1=50时RST为低电平,很明显R1=10k时是错误的,单片机一直处在复位状态时根本无法工作。出现这样的原因是由于RST引脚内含三极管,即便在截止状态时也会有少量截止电流,当R取的非常大时,微弱的截止电流通过就产生了高电平。

二、LED串联电阻的计算问题

通常红色贴片LED:电压1.6V-2.4V,电流2-20mA,在2-5mA亮度有所变化,5mA以上亮度基本无变化。

学好单片机必须了解的10个电路,一个都不能放过

三、端口出现不够用的情况

这时可以借助扩展芯片来实现,比如三八译码器74HC138来拓展

学好单片机必须了解的10个电路,一个都不能放过

学好单片机必须了解的10个电路,一个都不能放过

四、滤波电容

滤波电容分为高频滤波电容和低频滤波电容。

1、高频滤波电容一般用104容(0.1uF),目的是短路高频分量,保护器件免受高频干扰。普通的IC(集成)器件的电源与地之间都要加,去除高频干扰(空气静电)。

2、低频滤波电容一般用电解电容(100uF),目的是去除低频纹波,存储一部分能量,稳定电源。大多接在电源接口处,大功率元器件旁边,如:USB借口,步进电机、1602背光显示。耐压值至少高于系统最高电压的2倍。

五、三极管的作用

1、开关作用:

学好单片机必须了解的10个电路,一个都不能放过

LEDS6为高电平时截止,为低电平时导通。

限流电阻的计算:集电极电流为I,则基极电流为I/100(这里涉及到放大作用,集电极电流是基极的100倍),PN结电压0.7V,R=(5-0.7)/(I/100)

2、放大作用:

集电极电流是基极电流的100倍

3、电平转换:

学好单片机必须了解的10个电路,一个都不能放过

当基极为高电平时,三极管导通,右侧的导线接地为低电平,当基极为低电平时,三极管截止,输出高电平。

六、数码管的相关问题

学好单片机必须了解的10个电路,一个都不能放过

数码管点亮形成的数字由a,b,c,d,e,f,e,dp(小数点)构成,字模及真值表如上图。

七、电流电压驱动问题

由于单片机输出有限,当负载很多的时候需要另外加驱动芯片 ,比如74HC245

八、上拉电阻

上拉电阻选取原则

1、从节约功耗及芯片灌电流能力考虑应当足够大;电阻大,电流小。

2、从确保足够的驱动电流考虑应当足够小;电阻小,电流大。

3、对于高速电路,过大的上拉电阻可能会导致边沿变平缓。

综合考虑:上拉电阻常用值在1K到10K之间选取,下拉同理。

上下拉电阻

上拉就是将不确定的信号通过一个电阻嵌位在高电平,下拉同理。

1、电平转换,提高输出电平参数值。

2、OC门必须加上拉电阻才能使用。

3、加大普通IO引脚驱动能力。

4、悬空引脚上下拉抗干扰。

九、晶振和复位电路

晶振电路

1、晶振选择:

根据实际系统需求选择,6M,12M,11.0592M,20M等待

2、负载电容:

对地接2个10到30pF的电容即可,常用20pF。

3、万用表测晶振:

直接用红表笔对晶振引脚,黑表笔接GND,测量电压即可。

复位电路

复位

把单片机内部电路设置成为一个确定的状态,所有的寄存器初始化。

51单片机的复位时间大约在2个机械周期左右,具体需要看芯片数据手册。

一般通过复位芯片或者复位电路,具体的阻容参数的计算,通过google查找。

十、按键抖动及消除

按键也是机械装置,在按下或放开的一瞬间会产生抖动,如下图:

学好单片机必须了解的10个电路,一个都不能放过

学好单片机必须了解的10个电路,一个都不能放过

消除方法有两种:软件除抖和硬件除抖,其中硬件除抖是应用了电容对高频信号短路的原理。

软件除抖是检测出键闭合后执行一个延时程序,产生5ms~10ms的延时,让前沿抖动消失后再一次检测键的状态,如果仍保持闭合状态电平,则确认为真正有键按下。

<think>好的,我现在需要帮助用户设计一个4位动态显示电路的Verilog代码,显示内容是“学好”的后四位。首先,我需要理解动态显示的基本原理。动态显示是通过分时轮流点亮各个数码管,利用人眼的视觉暂留效应,看起来像是同时显示。这样可以节省IO,减少功耗。 接下来,我得确定显示的内容。用户提到显示“学好后四位”,但“学好”可能是指某个特定的编码,比如在数码管上显示字符或数字。通常数码管显示的是十六进制数字或一些特定字符,所以可能需要将“学好后四位”转换为对应的段码。比如,假设“学好后四位”对应的是四个特定的数字或字母,比如“A”、“B”、“C”、“D”,或者具体的数字如“1234”。但用户没有明确说明,可能需要进一步确认,但按照常见情况,可能用户希望显示学号的后四位数字,比如“2023”中的后四位“2023”,或者自定义的四个字符。这里可能需要假设用户需要显示四个数字,例如“2023”或者其他,但用户没有具体说明,所以可能需要用示例数字,比如“2023”,或者用“学好后四位”对应的某种编码。但为了通用性,可能需要在代码中留出段码的查找表,让用户自行填入需要的段码。 然后,设计思路应该是:使用计数器生成扫描时钟,分时选择每一位数码管,并输出对应的段码。四位动态显示通常需要4个位选信号和8个段选信号(假设是共阴或共阳数码管)。位选信号依次激活每一位,同时段码对应该位的显示内容。扫描频率需要足够高,比如1kHz左右,以避免闪烁。 接下来考虑Verilog代码的结构。模块需要有时钟输入、复位信号,以及位选(seg_sel)和段选(seg_data)输出。内部需要一个计数器来分频,生成扫描时钟。例如,系统时钟是50MHz,要分频到1kHz的扫描频率,每个数码管的刷新率是250Hz(因为四位轮流,所以1kHz/4=250Hz),这样人眼不会感觉到闪烁。 然后需要一个状态机或计数器来选择当前显示的位,循环从0到3。同时,需要根据当前位选择对应的段码数据。例如,四位数字存储在一个寄存器数组中,根据位选索引取出对应的段码。 数码管的段码表需要预先定义,比如0~9的七段码,可能还包括一些字母。假设用户需要显示的数字是四个,比如2023,那么对应的段码就是2、0、2、3的编码。需要根据数码管的类型(共阴或共阳)确定段码是高电平有效还是低电平有效。 还需要注意位选信号是低电平有效还是高电平有效,这取决于硬件连接。例如,如果是共阴数码管,位选可能为低电平选中,而段码为高电平点亮。 代码的大致结构可能如下: 模块定义: 输入clk, rst_n; 输出reg [3:0] seg_sel; 输出reg [7:0] seg_data; 内部信号: 计数器用于分频,生成扫描时钟; 位选计数器,循环0~3; 存储四位显示数据的寄存器; 段码查找表; 分频部分:每当时钟计数到一定值时,切换位选。例如,50MHz的时钟,要分频到1kHz扫描,每个位显示的时间是1ms。50MHz的周期是20ns,所以1ms需要计数50000次。因此计数器需要从0到49999,当计数到最大值时,切换位选。 位选计数器:每1ms加1,循环0到3,对应四位。 段码选择:根据当前位选,从四位数据中选择对应的段码。 段码表:可以用case语句或查找表实现,将数字转换为七段码(加上小数点可能为8位)。 复位信号处理:复位时,初始化计数器、位选和显示数据。 测试部分可能需要将四位数据设置为需要的值,比如2023,对应的四个数字的段码。 现在,可能存在一些问题需要确认:比如数码管的类型(共阴/共阳),段码的顺序(a~g对应哪一位),是否需要小数点。但用户没有给出这些细节,所以可能需要做一般假设,例如共阴数码管,段码a为最高位,或者根据常见的编码表。例如,假设段码顺序是dp, g, f, e, d, c, b, a,共阴的话,段码高电平点亮。例如,数字0的段码是0x3F(00111111),其中a段是最低位?或者不同的开发板可能有不同的接线,需要根据实际情况调整。所以代码中可能需要注释说明段码的对应关系,或者让用户根据实际情况修改段码表。 综上,代码的大致步骤: 1. 分频计数器,生成扫描时钟。 2. 位选计数器循环0-3。 3. 根据位选选择对应的显示数据。 4. 将数据转换为段码输出。 5. 位选信号根据当前位选激活对应的位。 现在,用户需要显示的是学号的后四位,但具体数字未给出。所以代码中可能需要定义一个四位寄存器,例如display_data,存储四个数字,如0、1、2、3,用户可以根据需要修改。 例如,假设学号后四位是2023,则display_data = {2,0,2,3}。 接下来,编写Verilog代码: 模块声明: module dynamic_display( input clk, // 系统时钟,例如50MHz input rst_n, // 复位信号,低有效 output reg [3:0] seg_sel, // 位选信号,低有效 output reg [7:0] seg_data // 段选信号,包括小数点 ); 内部计数器: reg [15:0] cnt; // 分频计数器,假设50MHz到1kHz,需要计数50000次,需要16位 reg [1:0] sel; // 位选计数器,0-3 reg [3:0] display_data [0:3]; // 四位显示数据,每个元素4位(0-9) 分频逻辑: always @(posedge clk or negedge rst_n) begin if (!rst_n) begin cnt <= 16'd0; sel <= 2'd0; end else begin if (cnt == 16'd49999) begin // 50MHz / 50000 = 1kHz cnt <= 16'd0; sel <= sel + 1'b1; // 每次切换位选 end else begin cnt <= cnt + 1'b1; end end end 位选信号生成: always @(*) begin case(sel) 2'd0: seg_sel = 4'b1110; // 选中第一位(共阴,低有效) 2'd1: seg_sel = 4'b1101; 2'd2: seg_sel = 4'b1011; 2'd3: seg_sel = 4'b0111; default: seg_sel = 4'b1111; endcase end 段码转换: always @(*) begin case(display_data[sel]) 4'h0: seg_data = 8'h3f; // 0的段码,假设共阴,a段为最低位 4'h1: seg_data = 8'h06; 4'h2: seg_data = 8'h5b; 4'h3: seg_data = 8'h4f; 4'h4: seg_data = 8'h66; 4'h5: seg_data = 8'h6d; 4'h6: seg_data = 8'h7d; 4'h7: seg_data = 8'h07; 4'h8: seg_data = 8'h7f; 4'h9: seg_data = 8'h6f; default: seg_data = 8'h00; // 其他情况不显示 endcase end 初始化显示数据: initial begin // 假设学号后四位是2023,则存储为2,0,2,3 display_data[0] = 4'd2; display_data[1] = 4'd0; display_data[2] = 4'd2; display_data[3] = 4'd3; end endmodule 不过,在Verilog中,数组的初始化可能需要使用generate或者在复位时赋值。另外,display_data的初始化应该在复位时完成,而不是使用initial块,因为有些FPGA可能不支持initial。因此,可以修改为: always @(posedge clk or negedge rst_n) begin if (!rst_n) begin display_data[0] <= 4'd2; display_data[1] <= 4'd0; display_data[2] <= 4'd2; display_data[3] <= 4'd3; end end 或者直接硬编码在段码转换的查找中,根据sel的值选择对应的数字。但可能需要更灵活的方式,让用户自行修改display_data的值。 另外,位选信号可能要根据硬件设计进行调整,比如是否反相,或者不同的位选顺序。例如,有些开发板可能第一位是最左边的数码管,而有些是最右边,所以需要根据实际硬件调整seg_sel的顺序。 此外,段码的编码是否正确,需要根据具体的数码管型号来确定。例如,如果是共阳数码管,段码需要取反。例如,共阳的0的段码是0xC0(11000000),而共阴的是0x3F(00111111)。所以用户需要根据实际情况修改段码表。 最后,测试这个模块时,需要连接到FPGA的时钟和数码管引脚,并确保位选和段选的极性正确。可能需要参考开发板的手册来确认引脚分配和极性设置,如引用[2]中提到,研究管脚定义和推荐的PCB layout非常重要[^2]。 总结,代码的结构大致正确,但需要注意段码和位选的极性,以及显示数据的初始化方式。此外,扫描频率的设置也需要合理,避免闪烁。</think>以下是用Verilog实现4位动态显示电路的代码设计和实现步骤: ### 一、设计原理 动态显示通过分时复用方式轮流点亮4位数码管,利用人眼视觉暂留效应实现稳定显示效果。每位数码管显示时间约1ms,刷新频率250Hz(1ms*4位)。硬件采用共阴数码管时,位选信号低电平有效,段选信号高电平有效[^2]。 ### 二、Verilog代码实现 ```verilog module dynamic_display( input clk, // 50MHz时钟 input rst_n, // 复位信号 output reg [3:0] seg_sel, // 位选信号(低有效) output reg [7:0] seg_data // 段选信号(a-g+dp) ); // 分频计数器生成1ms扫描周期 reg [15:0] scan_cnt; always @(posedge clk or negedge rst_n) begin if(!rst_n) scan_cnt <= 16'd0; else scan_cnt <= (scan_cnt == 16'd49999) ? 16'd0 : scan_cnt + 1; end // 数码管位选控制 reg [1:0] sel; always @(posedge clk or negedge rst_n) begin if(!rst_n) sel <= 2'd0; else if(scan_cnt == 16'd49999) sel <= sel + 1; end // 显示数据存储(示例显示"2023") reg [3:0] disp_data [0:3]; always @(posedge clk) begin disp_data[0] <= 4'd2; // 个位 disp_data[1] <= 4'd0; // 十位 disp_data[2] <= 4'd2; // 百位 disp_data[3] <= 4'd3; // 千位 end // 位选译码(共阴数码管) always @(*) begin case(sel) 2'd0: seg_sel = 4'b1110; 2'd1: seg_sel = 4'b1101; 2'd2: seg_sel = 4'b1011; 2'd3: seg_sel = 4'b0111; default: seg_sel = 4'b1111; endcase end // 段选译码(共阴数码管) always @(*) begin case(disp_data[sel]) 4'd0: seg_data = 8'b0011_1111; // 0 4'd1: seg_data = 8'b0000_0110; // 1 4'd2: seg_data = 8'b0101_1011; // 2 4'd3: seg_data = 8'b0100_1111; // 3 4'd4: seg_data = 8'b0110_0110; // 4 4'd5: seg_data = 8'b0110_1101; // 5 4'd6: seg_data = 8'b0111_1101; // 6 4'd7: seg_data = 8'b0000_0111; // 7 4'd8: seg_data = 8'b0111_1111; // 8 4'd9: seg_data = 8'b0110_1111; // 9 default: seg_data = 8'b0000_0000; endcase end endmodule ``` ### 三、关键设计要点 1. **时序控制**:使用50MHz时钟分频产生1ms扫描周期,每个数码管显示时间=1ms/4=250μs 2. **数据存储**:`disp_data`数组存储要显示的4位BCD码 3. **硬件适配**: - 共阳数码管需反转段选和位选信号 - 段码顺序需与实际PCB布局匹配 4. **参数配置**: ```verilog // 修改显示内容示例 disp_data[0] <= 4'd8; // 修改个位显示8 ``` ### 四、仿真验证建议 1. 前仿验证时序关系 2. 后仿加入实际布线延迟 3. 使用SignalTap观察实际扫描波形
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值