打印
[应用相关]

Proteus 仿真 STM32 之数码管

[复制链接]
1570|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-9-18 16:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
介绍
本博客适用于有一定单片机基础的学习爱好者。

Proteus仿真stm32第二集——数码管仿真

首先理解数码管的状态 7段数码管长包含7段发光二极管和一个小数点(其实也是一个发光二极管),要让数码管显示想要显示的值很简单,只需要让相应的发光二极管发光即可,这里还分共阳极和共阴极(本文选用共阳极),具体介绍参考博客:数码管介绍

懂了发光原理之后就很简单,如何让stm32芯片来配置相应的管脚值即可。

器件
器件选择
打开Proteus,元器件模式选择stm32f103c8系列(103系列的都行,c等字母编号代表不同的管脚数量),其余参考下面的器件。74LS245是驱动增强型芯片,没有实际作用仿真可以不放(当然如果要做成实物是必须要的)



部分器件没用,只是之前其他仿真添加的不用管。

摆放器件 (如图所示)



引脚编辑,这个参考上一篇文章 (再提示一遍在左边栏的终端模式里!)

选择其中一个74LS245作为a到dp的驱动,另一个作为位选的驱动(这个很关键,为之后的动态数码管做铺垫),引脚分配参考上图,我们使用GPIOB口作为本次仿真端口,16个口够用了。

代码编写
首先配置GPIOB口,新建seg.c和seg.h在HAREWARE文件夹,编写如下

seg.h文件
#ifndef __SEG_H
#define __SEG_H
void Seg_Init(void);
void Seg_Tran(unsigned char *pucSeg_Char, unsigned short *pucSeg_Code);
void Seg_Disp(unsigned short *pucSeg_Code, unsigned char ucSeg_Pos);
#endif
这个说一下本来应该参照正常写法写 u8 或者 uint8_t, 但是它的typedef在一个叫stdint.h的头文件里,打开这个头文件,诶!不就是unsigned char吗,所以这里写u8 或者unsigned char都是可以的,作者的编译器这里写uint8_t老是给警告,为了不让它警告就写unsigned char了。



seg.c文件
#include "stm32f10x.h"                  // Device header
#include "seg.h"

void Seg_Init(void)
{
                //声明一个结构体,名字是GPIO_InitStructure
        GPIO_InitTypeDef GPIO_InitStructure;
        //使能GPIOC的时钟,ENABLE代表使能
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//GPIOB

        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出

        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_All; // 选中所有端口

        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;  // 最大反转速度

        GPIO_Init(GPIOB,&GPIO_InitStructure);        // 初始化
       
}

void Seg_Tran(uint8_t *pucSeg_Char, uint16_t *pucSeg_Code)
{
        uint8_t i, j = 0;
        uint16_t ucSeg_Code;
       
        for(i = 0; i < 8; i++, j++)
        {
                switch(pucSeg_Char[j])
                {
                        case '0': ucSeg_Code = 0x00c0; break; // dp g f e d c b a
                        case '1': ucSeg_Code = 0x00f9; break;    // 1 1 1 1 1 0 0 1
                        case '2': ucSeg_Code = 0x00a4; break;    // 1 0 1 0 0 1 0 0
                        case '3': ucSeg_Code = 0x00b0; break;    // 1 0 1 1 0 0 0 0
                        case '4': ucSeg_Code = 0x0099; break;    // 1 0 0 1 1 0 0 1
                        case '5': ucSeg_Code = 0x0092; break;    // 1 0 0 1 0 0 1 0
                        case '6': ucSeg_Code = 0x0082; break;    // 1 0 0 0 0 0 1 0
                        case '7': ucSeg_Code = 0x00f8; break;    // 1 1 1 1 1 0 0 0
                        case '8': ucSeg_Code = 0x0080; break;    // 1 0 0 0 0 0 0 0
                        case '9': ucSeg_Code = 0x0090; break;    // 1 0 0 1 0 0 0 0
                        case 'A': ucSeg_Code = 0x0088; break;    // 1 0 0 0 1 0 0 0
                        case 'B': ucSeg_Code = 0x0083; break;    // 1 0 0 0 0 0 1 1
                        case 'C': ucSeg_Code = 0x00c6; break;    // 1 1 0 0 0 1 1 0
                        case 'D': ucSeg_Code = 0x00A1; break;    // 1 0 1 0 0 0 0 1
                        case 'E': ucSeg_Code = 0x0086; break;    // 1 0 0 0 0 1 1 0
                        case 'F': ucSeg_Code = 0x008E; break;    // 1 0 0 0 1 1 1 0
                        case 'H': ucSeg_Code = 0x0089; break;    // 1 0 0 0 1 0 0 1
                        case 'L': ucSeg_Code = 0x00C7; break;    // 1 1 0 0 0 1 1 1
                        case 'N': ucSeg_Code = 0x00C8; break;    // 1 1 0 0 1 0 0 0
                        case 'P': ucSeg_Code = 0x008c; break;    // 1 0 0 0 1 1 0 0
                        case 'U': ucSeg_Code = 0x00C1; break;    // 1 1 0 0 0 0 0 1
                        case '-': ucSeg_Code = 0x00bf; break;    // 1 0 1 1 1 1 1 1
                        default:  ucSeg_Code = 0x00ff;           // 1 1 1 1 1 1 1 1
                }
                if (pucSeg_Char[j+1] == '.')
                {
                        ucSeg_Code &= 0x007f;                // 点亮小数点
                        j++;
                }
                pucSeg_Code = ucSeg_Code;
        }
}
       
void Seg_Disp(uint16_t *pucSeg_Code,uint8_t ucSeg_Pos)
{
        uint16_t temp = 0x0100;
        temp = temp << ucSeg_Pos;
        GPIO_Write(GPIOB,pucSeg_Code[ucSeg_Pos] | temp);
}


这个得说明一下,初始化很简单,配置所有的GPIOB口为推挽输出的形式,最大反转频率50MHz,字符串转变函数:传入字符串的首字符指针和编码的首指针,字符都是常见的uint8_t足够,编码和51单片机同,GPIOB口一共有16位可用端口,因此需要使用uint16_t,具体编码如果有兴趣就自己算,不算复杂,略过。数码管显示函数:由于GPIOB 的 PB0 ~ PB7用来控制编码,因此使用PB8 ~ PB15来作为位选器。初始temp值 0x0100 = 0000 0001 0000 0000,相当于选中了PB8,通过传参来调整需要打开的数码管。

main.c文件
#include "stm32f10x.h"
#include  "led.h"  // led
#include "delay.h"        // 延时
#include "key.h"        // 按键
#include "seg.h"        // 数码管

uint8_t pucSeg_Char[12] = {'0','1','2','3','4','5','6','7'};         // 显示字符
uint16_t pucSeg_Code[8];         // 显示代码
uint8_t ucSeg_Pos;                         // 显示位置
int main(void)
{
        delay_init();
        Seg_Init();
        ucSeg_Pos = 0;
        while(1){  //主循环
                Seg_Tran(pucSeg_Char,pucSeg_Code);
                Seg_Disp(pucSeg_Code,ucSeg_Pos);
                if (++ucSeg_Pos == 8)
                        ucSeg_Pos = 0;
        }
}

多余的头文件可要可不要,对于这个仿真没什么用。这里新增了一些变量来实现数码管的显示,更改字符串的值即可在数码管显示相应的内容。



静态数码管就是这样,如果需要动态数码管,简单的可以在主循环中添加延时函数,并适当更改字符串,复杂的则需要定时器的帮助以实现动态显示,这个有机会再分享吧。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/2302_80954675/article/details/142144688

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2028

主题

15903

帖子

13

粉丝