STM32之---数码管动态扫描

       如果按照惯例,第一个实验一般是LED流水灯,但是我相信大家的胃口绝不仅仅满足于区区一个流水灯,因此给出了一个稍微复杂一点的实验,这个实验就是通过动态扫描的方式让这8个数码管分别显示0~7这8个数字。在这个实验中,大家将正式迈入STM32的开发大门。

       上图为实验的原理图,8个数码管为共阴极数码管,它们的每一段分别接在一起,分别形成了a、b、c、d、e、f、g和h这8个信号,这8个信号分别由74HC245的管脚B0~B7来控制,而74HC245 是一种三态输出、八路信号收发器,顾名思义,它可以用来发送信号,也可以用来接收信号,当管脚DIR=0时,信号从B0~B7输出到A0~A7,当管脚DIR=1时,信号从A0~A7输出到B0~B7。它的A0~A7这8个管脚分别接到STM32F103C8的PB0~PB7管脚,DIR管脚在这里固定拉高,所以信号从A0~A7输出到B0~B7;它们的位选信号分别由74LS138的Y0~Y8来控制,而74LS138是一颗译码器,输入端三个信号ABC,这三个管脚分别接到STM32F103C8的PA5、PA6和PA7上。74LS138真值表如下:

编码输入值

译码输出值

C

B

A

Y7

Y6

Y5

Y4

Y3

Y2

Y1

Y0

0

0

0

0

0

0

0

0

0

0

1

0

0

1

0

0

0

0

0

0

1

0

0

1

0

0

0

0

0

0

1

0

0

0

1

1

0

0

0

0

1

0

0

0

1

0

0

0

0

0

1

0

0

0

0

1

0

1

0

0

1

0

0

0

0

0

1

1

0

0

1

0

0

0

0

0

0

1

1

1

1

0

0

0

0

0

0

0

1、本次编程要达到的目标:让这8个数码管分别显示1~8这8个数字

2、原理:这8个数码管的8个段位全部接在了一起,要想分别显示1~8这8个不同的数字,似乎不太可能,但是它们的位选信号是独立的,如果同一时刻只选定一位,并向该位数码管送入特定的数字,按此逐个送出特定的数字,如此一来,8个数码管就可以分别被点亮了,但是这样看到的始终只有一个数码管在亮,而不是所有的数码管同时亮,不用急,提高给每个数码管送数据的频率就可以骗过人的眼睛,让人眼看着这8个数码管都是同时分别显示8个数字。

3、数码管动态显示的思路:

         ①送清屏段码数据,也就是让数码管不显示数据,否则当前送出去的数据很可能就是乱码,把位选信号一打开就会导致某位数码管显示乱码。

         ②通过位选信号选定特定编号的数码管,由于①步骤的存在,此时该位数码管不显示数据。

         ③将该位数码管要显示的数据送出去

         ④延迟一段时间以保证该位数码管在每轮显示周期中被点亮足够的时间,否则该位数码管最终显示的图样会比较暗。

         ⑤送清屏段码数据,否则进入到⑥的时候,刚刚被被显示的图样会在下一位数码管上被短暂显示。

         ⑥改变位选信号,使得下一位数码管开始显示属于它的数据。

         ⑦进入到③

 4、软件规划:

①设置好STM32F103C8的系统时钟和外设时钟。

由于使用了GPIOA和GPIOB,因此需要将这两个端口的时钟打开,于是才有了如下的语句。

//开启B端口的时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);  

//开启A端口的时钟       

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);  

另外,由于PB3和PB4的管脚上电复位后默认为JTAG信号脚,而PB0~PB7被用于给数码管送出显示数据,因此必须将这两个管脚复用为普通的GPIO管脚,于是才有了如下的语句:

//如果不加这条语句程序显示就会出错,即没有打开端口复用功能的时钟配置  

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

②设置GPIOA和GPIOB的管脚特性。数码管的段选信号和位选信号都设置为通用推挽输出,详情见smg.c的GPIOINIT函数。

③编写数码管驱动模块

下面的位选编码需要参看74LS138解码器,由于编码管脚为PA5/PA6/PA7这三个管脚,//所以,编码值只是这三个脚对应的位的变化,PB[7:5]的值时从000到111这8个数值//的变化,而PB[4:0]=00000,于是才有了下面这个数组的各元素的值。

smg.h

//宏定义
#define IS_SMGINDEX_RANGE_IN_MAX(SMGINDEX) ((SMGINDEX==0)|| \
																					  
                                           (SMGINDEX==1)|| \
																					  
                                           (SMGINDEX==2)|| \
																					  
                                           (SMGINDEX==3)|| \
																					  
                                           (SMGINDEX==4)|| \
																					  
                                           (SMGINDEX==5)|| \
																					  
                                           (SMGINDEX==6)|| \
																					  
                                           (SMGINDEX==7)|| \
																					  
                                           (SMGINDEX==8))
																					 

#define SMGDXPORT GPIOB
#define SMGWXPORT GPIOA
#define SMGDX GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7
#define SMGWX GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7																					 
																					 
//自定义数据类型
//定义枚举类型
//定义结构体类型
//定义共用体类型



//函数声明
extern void ClearSmgScreen(void);
extern void SelSmg(u8 SmgIndex);
extern void SendSmgDispData(u8 DispData);

extern void GPIOINIT(void);


//----------------------------------------------------------------------//
smg.c

#include"stm32f10x.h"
#include"smg.h"

u8 smgduan[]={0x3F/*0*/, 0x06/*1*/, 0x5B/*2*/, 0x4F/*3*/, 0x66/*4*/, 0x6D/*5*/, 
                  0x7D/*6*/, 0x07/*7*/,0x7F/*8*/, 0x6F/*9*/};//段选
u8 smgwei[8]={0x00,0x20,0x40,0x60,0x80,0xa0,0xc0,0xe0}; //位选
/******************************************/
/*
@function:清屏
@input:NONE
@output:NONE
*/
void ClearSmgScreen(void)
{
	GPIO_Write(SMGDXPORT,( u16)(0));
}
/******************************************/
/*
@function:选定某位数码管
@input:NONE
@output:NONE
*/
void SelSmg(u8 SmgIndex)
{
	assert_param(IS_SMGINDEX_RANGE_IN_MAX(SmgIndex));
	GPIO_Write(SMGWXPORT,( u16)(smgwei[SmgIndex]));
}
/******************************************/
/*
@function:送出具体显示数据
@input:NONE
@output:NONE
*/
void SendSmgDispData(u8 DispData)
{
	GPIO_Write(SMGDXPORT,( u16)(smgduan[DispData]));
}

void GPIOINIT()	  //端口初始化函数
{
/*********定义一个GPIO_InitTypeDef 类型的结构体**********/
	GPIO_InitTypeDef GPIO_InitStructure;

/*********选择要控制的GPIOx的引脚**********/
	GPIO_InitStructure.GPIO_Pin=SMGDX;

/*********设置引脚模式为通用推完输出**********/
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;

/*********设置引脚速率为50MHZ**********/
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

/*初始化相应的GPIOB的设置*/
	GPIO_Init(SMGDXPORT,&GPIO_InitStructure);
	
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);//把调试设置普通IO口

/*********选择要控制的GPIOx的引脚**********/
	GPIO_InitStructure.GPIO_Pin=SMGWX;

/*********设置引脚模式为通用推完输出**********/
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;

/*********设置引脚速率为50MHZ**********/
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

/*初始化相应的GPIOA的设置*/
	GPIO_Init(SMGWXPORT,&GPIO_InitStructure); 	
}

④延迟模块

delay.h
extern void delayms(u32 i);

//---------------------------------------------------------------//
delay.c
#include"stm32f10x.h"
void delayms(u32 i)
{
	u32 temp;
	SysTick->LOAD=9000*i;	  //设置重装数值, 72MHZ时
	SysTick->CTRL=0X01;		//使能,减到零是无动作,采用外部时钟源
	SysTick->VAL=0;			//清零计数器
	do
	{
		temp=SysTick->CTRL;	   //读取当前倒计数值
	}
	while((temp&0x01)&&(!(temp&(1<<16))));	//等待时间到达
	SysTick->CTRL=0;	//关闭计数器
	SysTick->VAL=0;		//清空计数器
}

⑤主函数模块

main.c

#include"stm32f10x.h"
#include"smg.h"
#include"delay.h"

void RCCINIT() //系统初始化函数
{
	SystemInit();
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);		  //开启B端口的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);		  //开启A端口的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//如果不加这条语句程序显示就会出错,即没有打开端口复用功能的时钟配置
}

int main()
{	
	u8 i;
	RCCINIT();
	GPIOINIT();
		  
	while(1)
	{
		
		for(i=0;i<8;i++)			
		{
			ClearSmgScreen();
            SelSmg(i);
            SendSmgDispData(i);
			delayms(2);
		}
	}	
}

5、工程结构

6、最终显示结果

OK,大功告成!

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值