51单片机的简单应用

    使用51单片机,2个74HC595和2个共阴数码管实现上电后从00到99显示,间隔1秒。

需要有电路连接图,C语言代码和整体电路的解读

首先你要知道74HC595的引脚功能,确立它的连接方式

img

DS:14脚,串行数据输入引脚,级联的话接上一级的Q7’。
OE:13脚,输出使能控制脚,它是低电才使能输出,所以接GND
ST_CP:12脚,存储寄存器时钟输入引脚。上升沿时,数据从移位寄存器转存带存储寄存器。
SH_CP:11脚,移位寄存器时钟引脚,上升沿时,移位寄存器中的数据整体后移,并接受新的数据(从DS输入)。
MR:10脚,低电平时,清空移位寄存器中已有的数据,一般不用,接高电平即可。
Q7’:9脚,串行数据输出引脚。当移位寄存器中的数据多于8位时,会把已有的位“挤出去”,就是从这里出去的。用于595的级联,将它接下一个74HC595的DS端。
Q1-Q7:1到7脚,并行输出引脚
————————————————
74HC595功能部分文章参考CSDN博主「牧子川」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_48764574/article/details/118463276

对应的电路图接法如下:

img

上图中,SDI、LOAD、SCLK分别是单片机的3个控制IO口(可以通过程序控制输出高、低电平即可),对应的是74HC595的数据输入端DS、装载时钟ST_CP、以及移位时钟SH_CP,附上简单的控制代码。
思路是对51单片机而言只用sbit定义3个控制端口即可,在100个循环内,得到0-99的个位、十位的段码数值,通过串行数据输入端DS、移位时钟SH_CP,将要输入的16位段码(个位8位+十位8位)存入两个74HC595的移位存储器,然后通过装载时钟ST_CP上升沿将十六位数据加载显示。

直接上代码:


#include "reg51.h"

typedef unsigned int u16;    //对系统默认数据类型进行重定义
typedef unsigned char u8;

//定义74HC595控制管脚
sbit SRCLK=P3^6;    //移位寄存器时钟输入
sbit RCLK=P3^5;        //存储寄存器时钟输入
sbit SER=P3^4;         //串行数据输入

//共阴不带小数点0-F段码
u8 LED_table2[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
                                    0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//要传输的16位段码
u16    LED_table;
                                    
/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能         : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出         : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
    while(ten_us--);    
}

/*******************************************************************************
* 函 数 名       : delay_ms
* 函数功能         : ms延时函数,ms=1时,大约延时1ms
* 输    入       : ms:ms延时时间
* 输    出         : 无
*******************************************************************************/
void delay_ms(u16 ms)
{
    u16 i,j;
    for(i=ms;i>0;i--)
        for(j=110;j>0;j--);
}

/*******************************************************************************
* 函 数 名         : hc595_write_data(u8 dat)
* 函数功能           : 向74HC595写入一个字节的数据
* 输    入         : dat:数据
* 输    出         : 无
*******************************************************************************/
//传一个74HC595数据
void hc595_write_data(u8 dat)
{
    u8 i=0;
    
    for(i=0;i<8;i++)//循环8次即可将一个字节写入寄存器中
    {
        SER=dat>>7;//优先传输一个字节中的高位
        dat<<=1;//将低位移动到高位
        SRCLK=0;
        delay_10us(1);
        SRCLK=1;
        delay_10us(1);//移位寄存器时钟上升沿将端口数据送入寄存器中    
    }
    RCLK=0;
    delay_10us(1);
    RCLK=1;//存储寄存器时钟上升沿将前面写入到寄存器的数据输出    
}

//传两个74HC595数据
void hc595_write_data2(u16 dat)
{
    u8 i=0;
    
    for(i=0;i<16;i++)//循环16次即可将两个字节写入寄存器中
    {
        SER=dat>>15;//优先传输两个字节中的高位
        dat<<=1;//将低位移动到高位
        SRCLK=0;
        delay_10us(1);
        SRCLK=1;
        delay_10us(1);//移位寄存器时钟上升沿将端口数据送入寄存器中    
    }
    RCLK=0;
    delay_10us(1);
    RCLK=1;//存储寄存器时钟上升沿将前面写入到寄存器的数据输出    
}

/*******************************************************************************
* 函 数 名       : main
* 函数功能         : 主函数
* 输    入       : 无
* 输    出         : 无
*******************************************************************************/
void main()
{    
    u8 i=0;
    u8 i1;    //i的个位
    u8 i2;    //i的十位
    u8 n=0;
    while(1)
    {            
        for(i=0;i<100;i++)//循环8次扫描8行、列
        {
            //每次循环先得到i的个位、十位段码
            i1=i%10;
            i2=i/10;
            for(n=0;n<16;n++)
            {        
                //先传十位段码,后传个位段码
                LED_table=(LED_table2[i2]<<8|LED_table2[i1]);    //括号加与不加都行
            }
            hc595_write_data2(LED_table);
            delay_ms(1000);        //1s延迟
        }        
        if(i==100) i=0;        //回到初值
    }        
}


以此将2个74HC595和2个共阴数码管实现上电后从00到99显示,间隔1秒。

你可以循环让一个计数器不断+1,同时io控制数码管

这个程序使用了一个 display 函数来输出数码管的数据。该函数接受两个参数,分别是需要显示的两个数字。在函数内部,我们首先输出第二个数码管的数据,然后输出第一个数码管的数据,最后锁存数据。在主函数中,我们使用两个循环来遍历数字 00 到 99,并调用 display 函数输出数据。每次输出后,我们使用 delay 函数延迟 1 秒,以实现显示间隔。


#include <reg51.h>

#define DATA_PIN P2_0
#define LATCH_PIN P2_1
#define CLK_PIN P2_2

unsigned char code LEDChar[] = {
    0xC0,  // '0'
    0xF9,  // '1'
    0xA4,  // '2'
    0xB0,  // '3'
    0x99,  // '4'
    0x92,  // '5'
    0x82,  // '6'
    0xF8,  // '7'
    0x80,  // '8'
    0x90,  // '9'
};

void delay(unsigned int ms) {
    unsigned int i, j;
    for (i = 0; i < ms; i++) {
        for (j = 0; j < 125; j++);
    }
}

void display(unsigned char data1, unsigned char data2) {
    unsigned char i;
    
    // 先输出第二个数码管的数据
    DATA_PIN = LEDChar[data2 % 10];
    CLK_PIN = 0;
    CLK_PIN = 1;
    
    DATA_PIN = LEDChar[data2 / 10];
    CLK_PIN = 0;
    CLK_PIN = 1;
    
    // 输出第一个数码管的数据
    DATA_PIN = LEDChar[data1 % 10];
    CLK_PIN = 0;
    CLK_PIN = 1;
    
    DATA_PIN = LEDChar[data1 / 10];
    CLK_PIN = 0;
    CLK_PIN = 1;
    
    // 输出完成,锁存数据
    LATCH_PIN = 0;
    LATCH_PIN = 1;
}

void main() {
    unsigned char i, j;
    
    while (1) {
        for (i = 0; i < 10; i++) {
            for (j = 0; j < 10; j++) {
                display(i, j);
                delay(1000);
            }
        }
    }
}

以下提供了一点使用51单片机、2个74HC595和2个共阴数码管实现上电后从00到99显示,间隔1秒的代码:

#include <reg51.h>

sbit latch = P2^0; // 74HC595锁存端口
sbit clock = P2^1; // 74HC595时钟端口
sbit data = P2^2; // 74HC595数据端口

unsigned char code num[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90}; // 共阴数码管的数字编码表,依次对应0-9

void delay(unsigned int t)
{
    unsigned int i, j;
    for(i = t; i > 0; i--)
        for(j = 110; j > 0; j--); // 微秒级延时函数
}

void send(unsigned char dat)
{
    unsigned char i;
    for(i = 0; i < 8; i++) {
        clock = 0;
        data = dat & 0x80; // 取出最高位
        dat <<= 1; // 左移一位,处理下一位数据
        clock = 1;
    }
}

void display(unsigned char num1, unsigned char num2)
{
    latch = 0;
    send(num[num2]); // 发送第二个数码管的数据
    send(num[num1]); // 发送第一个数码管的数据
    latch = 1; // 送出数据
}

void main()
{
    unsigned char i, j;
    for(i = 0; i < 100; i++) {
        for(j = 0; j < 50; j++) { // 等待1秒,通过50次延时实现
            display(i / 10, i % 10); // 显示当前数字
            delay(10); // 延时20微秒,共500次,等待1秒
        }
    }
}


说明:

代码中使用了三个端口,P2.0作为74HC595锁存端口,P2.1作为74HC595时钟端口,P2.2作为74HC595数据端口,可根据实际连接情况修改。

共阴数码管的数字编码表为 num[],根据具体型号可自行修改。

在主函数中使用两层循环,外层循环100次,内层循环50次,通过20微秒的延时等待实现1秒的效果,实现从00到99的循环显示。

在循环中通过 display() 函数实现显示,传入的两个参数分别为两个数码管要显示的数字。

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
下面是题目所需的电路连接图:

![电路连接图](https://i/

下面是使用51单片机,2个74HC595和2个共阴数码管实现上电后从00到99显示,间隔1秒的代码:


#include <reg51.h>

#define LED_PORT P0
#define LATCH_PIN P2_5
#define CLOCK_PIN P2_3
#define DATA_PIN P2_4

unsigned char code LED_TAB[] = {
    0xc0,  // 0 
    0xf9,  // 1 
    0xa4,  // 2 
    0xb0,  // 3 
    0x99,  // 4 
    0x92,  // 5 
    0x82,  // 6 
    0xf8,  // 7 
    0x80,  // 8 
    0x90,  // 9 
};

void delay_ms(unsigned int ms); // 延时函数
void hc595_send_byte(unsigned char dat); // 发送字节到74HC595

void main() {
    unsigned char i, j;
    LATCH_PIN = 1; // 和74HC595通信的IO初始化
    CLOCK_PIN = 0;
    DATA_PIN = 0;

    while (1) {
        for (i = 0; i < 10; i++) { // 十位数字
            for (j = 0; j < 10; j++) { // 个位数字
                hc595_send_byte(LED_TAB[i]); // 发送十位数字到74HC595
                hc595_send_byte(LED_TAB[j]); // 发送个位数字到74HC595
                LATCH_PIN = 0; // 上升沿锁存数据
                LATCH_PIN = 1;
                delay_ms(1000); // 间隔1秒
            }
        }
    }
}

void delay_ms(unsigned int ms) {
    unsigned int i, j;
    for (i = 0; i < ms; i++) {
        for (j = 0; j < 114; j++); // 1毫秒的延时
    }
}

void hc595_send_byte(unsigned char dat) {
    unsigned char i;
    for (i = 0; i < 8; i++) {
        CLOCK_PIN = 0;
        DATA_PIN = dat & 0x80

注释说明:

定义LED_PORT为P0口,用于控制数码管的LED灯;
定义LATCH_PIN为P2.5口,用于控制74HC595的锁存信号;
定义CLOCK_PIN为P2.3口,用于控制74HC595的时钟信号;
定义DATA_PIN为P2.4口,用于控制74HC595的数据信号;
定义LED_TAB数组,用于存储数字0~9的LED显示数据;
delay_ms函数用于实现毫秒级延时;
hc595_send_byte函数用于将一个字节发送到74HC595中;
在主程序中,使用两个for循环分别控制十位数字和个位数字,将它们分别发送到74HC595中,然后通过锁存信号将数据写入寄存器,最后延时1秒钟,实现数字的循环显示。
此程序需要使用Keil C编译器进行编译。同时,还需要连接上2个74HC595和2个共阴数码管等硬件设备,通过对应的引脚连接进行电路的搭建。

参考GPT和自己的思路,下面是使用51单片机、2个74HC595和2个共阴数码管实现上电后从00到99显示,间隔1秒的电路连接图和C语言代码:

电路连接图:

img

其中,P3.4、P3.5和P3.6分别连接到74HC595芯片的SER、RCLK和SRCLK引脚,P1.0~P1.4分别连接到共阴数码管的D1_Segment、D1_Digit、D2_Segment、D2_Digit引脚上,共阴数码管中的两个数码管并联连接到74HC595芯片的输出引脚上。

C语言代码:

#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int

sbit SRCLK = P3^6;
sbit RCLK = P3^5;
sbit SER = P3^4;

uchar code LED_DuanMa[10] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};

void delay_ms(uint x)
{
    uint i,j;
    for(i=x;i>0;i--)
    {
        for(j=114;j>0;j--);
    }
}

void HC595SendByte(uchar dat)
{
    uchar i;
    for(i=0;i<8;i++)
    {
        SRCLK = 0;
        SER = dat&0x80;
        dat <<= 1;
        SRCLK = 1;
    }
    RCLK = 0;
    RCLK = 1;
}

void main()
{
    uchar i,j;
    while(1)
    {
        for(i=0;i<10;i++)
        {
            for(j=0;j<10;j++)
            {
                HC595SendByte(LED_DuanMa[i]);
                HC595SendByte(LED_DuanMa[j]);
                delay_ms(1000);
            }
        }
    }
}

代码解读
1.定义了单片机的IO口和需要用到的数据类型。
2.定义了共阴数码管显示0-9的段码。
3.定义了一个延时函数delay_ms,用来实现1秒的延时。
4.HC595SendByte函数用于向74HC595芯片发送一个字节的数据。通过SER和SRCLK分别向74HC595芯片的串行输入和时钟输入发送数据,再通过RCLK向74HC595芯片的存储器时钟输入发送数据。
5.在主函数中,用两个循环嵌套来实现00-99的显示。每次循环中,先向第一个数码管发送十位数的段码,然后向第二个数码管发送个位数的段码,完成一次数字的显示。然后延时1秒钟,进入下一个循环。

【C语言代码】



```c
#include<reg52.h>
//*************************************
#define uint unsigned int
#define uchar unsigned char
//**************************************
sbit WREN=P3^5;      //写使能
sbit WR=P3^6;        //写
sbit CE=P3^7;        //片选使能

uchar code data_char[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,    //数码管0~9的显示段码
                                    0x7F,0x67,0x77,0x7C,0x39,0x5E, 
                                    0x79,0x71};

//**************************************
void delayms(uint);
void write_data(uchar);
//***************************************

void main()
{
    CE=1; 
    WREN=0;
    WR=1;
    while(1)
    {
        for(int i=0;i<100;i++)   //i为计数器,值从0~99进行变换之后刷新到LED上。
        {
            for(int j=0;j<8;j++)  //j为控制位选和段选的一个变量,值从0-1之间变换。
            {
                if(j==0)
                {
                    write_data(i%10);      //将i的个位数存入移位寄存器中
                    CE=0;
                    CE=1;
                }
                else
                {
                    write_data((i/10)%10);      //将i的十位数存入移位寄存器中
                    CE=0;
                    CE=1;
                }
                P2=0xff;          //将P2口的值赋为1ffff,则对应的数码管就会亮
                P0=data_char[i%10];   //data_char[]数组定义了相应的该值所对应的数字
                delayms(1);       //延时1ms,以保证能看到动态效果。
                P2=0x00;          //每关闭一位数码管,这里将P2口的值设置为0,则数码管关闭
                delayms(1);       
            }
        }
    }
}

void delayms(uint x)      //延迟x毫秒
{
    uint i,j;
    for(i=x;i>0;i--)
        for(j=110;j>0;j--);
}

void write_data(uchar dat)
{
    uchar mask;       //使用位操作的方法,逐次给595写入数据。
    mask=0x80;       //mask初始值为0x80,即二进制下最左边为1,其余为0。
    for(int i=0;i<8;i++)   //对应8位二进制的数据调用for循环,进行2进制位操作
    {
        WR=1;
        if(dat&mask)
            P2=1;
        else
            P2=0;
        mask=mask>>1;    //每次右移一位,以便将整个数据都传入输出引脚
        WR=0;
        WR=1;
    }
}

```
【整体电路的解读】
该电路分为两部分:主控板电路和数码管驱动电路。其中,主控板采用单片机AT89C51进行控制,通过 #include<reg52.h> 引入头文件实现对寄存器的操作。数码管驱动电路采用74HC595芯片进行驱动,将P0口和P2口分别接到8位串行输入、并行输出的移位存储寄存器。其中,P2口用来控制位选,P0口用来控制段选,通过不同的二进制代码,对应不同的数码管显示。同时,由于采用的是共阴连接方式的数码管,需要在控制端将高电平控制为低电平有效,即置0。

该程序中的delayms()函数用于进行时间延时,以实现数码管动态显示效果。delayms()函数具有两个参数,第一个参数为要延迟的时间(毫秒),第二个参数为控制时间精度的变量。在本程序中,固定为110,以保证在单片机频率为11.0592MHz的情况下,延时1毫秒。

在主程序中使用了两层for循环,第一层对应099的所有数字,第二层对应位选和段选。具体来说,由于74HC595芯片的存储字节为8位,因此在位选和段选中均需要将需要显示的数字拆分成两个数位,分别存入寄存器中。其中,i为计数器,值从099进行变换之后刷新到LED上。j为控制位选和段选的一个变量,值从0-1之间变换。

最终实现的效果是,数码管上的数值从00开始,以1的速度持续地增加,直至99后又从00开始,不断循环显示。

不知道你这个问题是否已经解决, 如果还没有解决的话:

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

你需要实现的就是一个串入并处的功能,间隔1秒更新一组数字实现显示数字的变化,循环往复即可