stm32学习笔记(7)数码管显示

提前说说

又是没写博客的一个周,每天过的都很难受。事实上,现在是正在学习的时间,我重新规整了学习计划,不像原来把每天自学学习时间的大部分时间给32了,现在基本两到三个小时左右。一是快期末了,得抽出时间复习了,二来文化课对我来说也十分重要,第三点就是还是得抽出时间陪陪女朋友的。好的是,自己学习的时长增多了,所以也不算太落后吧。每天中规中矩的看两次视频,基础部分视频一次看两遍。每天内容也不算多,但是感觉自己能吸收里面的知识。现在已经学到了pwm和输入捕获实验的地方,接下来就是显示屏的内容了。我决定先放放吧,每天看一节,剩余大部分时间主攻各个手册了,也算是彻底搞明白之前不会的点了。预计完成时间,六月底。
上个周学长学姐们给我们布置了任务,应用所学的知识完成数码管的显示。实验的总体难度是比较简单的,是一个很不错的练手机会,我觉得非常适合我们这些初学者。

废话不多说,开始吧

数码管显示实验

led数码管(LED Segment Displays)由多个发光二极管封装在一起组成“8”字型的器件,引线已在内部连接完成,只需引出它们的各个笔划,公共电极。数码管实际上是由七个发光管组成8字形构成的,加上小数点就是8个。这些段分别由字母a,b,c,d,e,f,g,dp来表示。

stm32学习笔记(7)数码管显示_第1张图片
上图左边部分就是数码管的正面,右边是背后的引脚及其对应部分。(每个字母代表着一横行或者一数列,Dp代表左部分右下脚的点) 每一行的中间就如图所示,接地Gnd就可以了。

任务就是通过按键,让数码管由0-9或者9-0,学完定时器中断的,学姐还让我们用定时器中断写一个数码管显示的自动累加功能。

代码总体比较简单,但是一定要认真写,指不定在哪就会出错了。

led.h

#ifndef __LED_H
#define __LED_H	 
#include "sys.h"

#define LED5 PBout(5)	// PB5
#define LED6 PBout(6)	// PB6	
#define LED7 PBout(7)	// PB7	
#define LED8 PBout(8)	// PB8	
#define LED9 PBout(9)	// PB9	
#define LED10 PBout(10)	// PB10	
#define LED11 PBout(11)	// PB11
#define LED12 PBout(12)
#define LED1 PAout(8)
void LED_Init(void);//初始化

		 				    
#endif

led.c

#include "led.h"



//GPIOB.5~GPIOB.13
void LED_Init(void)
{
 
 GPIO_InitTypeDef  GPIO_InitStructure;
 	
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	 //使能PA,PD端口时钟
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;			 
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 
 GPIO_Init(GPIOB, &GPIO_InitStructure);					
 GPIO_SetBits(GPIOB,GPIO_Pin_5);						 
 
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;			
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		
 GPIO_Init(GPIOB, &GPIO_InitStructure);					
 GPIO_SetBits(GPIOB,GPIO_Pin_6);
	
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;			 
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		
 GPIO_Init(GPIOB, &GPIO_InitStructure);					
 GPIO_SetBits(GPIOB,GPIO_Pin_7);
 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;			
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_Init(GPIOB, &GPIO_InitStructure);					
 GPIO_SetBits(GPIOB,GPIO_Pin_8);
 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;			
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_Init(GPIOB, &GPIO_InitStructure);					
 GPIO_SetBits(GPIOB,GPIO_Pin_9);
 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;			
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_Init(GPIOB, &GPIO_InitStructure);					 
 GPIO_SetBits(GPIOB,GPIO_Pin_9);
 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;			 
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_Init(GPIOB, &GPIO_InitStructure);					
 GPIO_SetBits(GPIOB,GPIO_Pin_10);
 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;			 
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_Init(GPIOB, &GPIO_InitStructure);					 
 GPIO_SetBits(GPIOB,GPIO_Pin_11);
 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;			 
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		
 GPIO_Init(GPIOB, &GPIO_InitStructure);					
 GPIO_SetBits(GPIOB,GPIO_Pin_12);
 

 	
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD, ENABLE);	 //使能PA,PD端口时钟
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;				 
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		
 GPIO_Init(GPIOA, &GPIO_InitStructure);					
 GPIO_SetBits(GPIOA,GPIO_Pin_8);						 

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;	    		
 GPIO_Init(GPIOD, &GPIO_InitStructure);	  				
 GPIO_SetBits(GPIOD,GPIO_Pin_2); 						
}

key.h

#ifndef __KEY_H
#define __KEY_H	 
#include "sys.h"
  

#define KEY0  GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)//读取按键0
#define KEY1  GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)//读取按键1
#define WK_UP   GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)//读取按键2 
 

#define KEY0_PRES	1		//KEY0  
#define KEY1_PRES	2		//KEY1 
#define WKUP_PRES	3		//WK_UP  

void KEY_Init(void);//IO初始化
u8 KEY_Scan(u8 mode);  	//按键扫描函数					    
#endif

key.c

#include "key.h"
#include "delay.h"

//按键初始化函数 
//PA15和PC5 设置成输入
void KEY_Init(void)
{
	
	GPIO_InitTypeDef GPIO_InitStructure;

 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE);//使能PORTA,PORTC时钟

	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);//关闭jtag,使能SWD,可以用SWD模式调试
	
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_15;//PA15
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
 	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA15
	
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_5;//PC5
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
 	GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOC5
 
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;//PA0
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0设置成输入,默认下拉	  
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.0
	
} 
//按键处理函数
//返回按键值
//mode:0,不支持连续按;1,支持连续按;
//返回值:
//0,没有任何按键按下
//KEY0_PRES,KEY0按下
//KEY1_PRES,KEY1按下
//WKUP_PRES,WK_UP按下 
//注意此函数有响应优先级,KEY0>KEY1>WK_UP!!
u8 KEY_Scan(u8 mode)
{	 
	static u8 key_up=1;//按键按松开标志
	if(mode)key_up=1;  //支持连按		  
	if(key_up&&(KEY0==0||KEY1==0||WK_UP==1))
	{
		delay_ms(10);//去抖动 
		key_up=0;
		if(KEY0==0)return KEY0_PRES;
		else if(KEY1==0)return KEY1_PRES;
		else if(WK_UP==1)return WKUP_PRES; 
	}else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1; 	     
	return 0;// 无按键按下
}

按键实验基本就是照搬原子哥的,我觉得挺好用的。
main.c

#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "key.h"
//上:5.中中 6.左上 7.上中 8.右上
//下:9.左下 10.下中 11.右下 12.点

void Light_0(void)
{
    LED6=1;
		LED7=1;
		LED8=1;
		LED9=1;
		LED10=1;
		LED11=1;
}

void Light_1(void)
{
	LED8=1;
	LED11=1;
}

void Light_2(void)
{
	LED7=1;
	LED8=1;
	LED5=1;
	LED9=1;
	LED10=1;
}

void Light_3(void)
{
	LED5=1;
	LED8=1;
	LED7=1;
	LED11=1;
	LED10=1;
}

void Light_4(void)
{
	LED6=1;
	LED5=1;
	LED8=1;
	LED11=1;
}

void Light_5(void)
{
	LED7=1;
	LED6=1;
	LED5=1;
	LED11=1;
	LED10=1;
}

void Light_6(void)
{
	LED7=1;
	LED6=1;
	LED5=1;
	LED9=1;
	LED10=1;
	LED11=1;
}

void Light_7(void)
{
	LED7=1;
	LED8=1;
	LED11=1;
}

void Light_8(void)
{
	LED5=1;
	LED6=1;
	LED7=1;
	LED8=1;
	LED9=1;
	LED10=1;
	LED11=1;
}

void Light_9(void)
{
	LED5=1;
	LED6=1;
	LED7=1;
	LED8=1;
	LED10=1;
	LED11=1;
}

void Select_LED(u8 i)
{
	switch(i)
	{
		case 0:Light_0();break;
		case 1:Light_1();break;
		case 2:Light_2();break;
		case 3:Light_3();break;
		case 4:Light_4();break;
		case 5:Light_5();break;
		case 6:Light_6();break;
		case 7:Light_7();break;
		case 8:Light_8();break;
		case 9:Light_9();break;
	}
	
	
}

void RESET_LED(void)
{
	 LED5=0;
	LED6=0;
	LED7=0;
	LED8=0;
	LED9=0;
	LED10=0;
	LED11=0;
	LED12=0;
}



void TIM3_Int_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能

	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 计数到5000为500ms
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
 
	TIM_ITConfig(  //使能或者失能指定的TIM中断
		TIM3, //TIM2
		TIM_IT_Update ,
		ENABLE  //使能
		);
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
	NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

	TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设
							 
}

void TIM3_IRQHandler(void)   //TIM3中断
{
	 static u8 u=0;
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 
		{
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx的中断待处理位:TIM 中断源 
	//	Select_LED(u);
	//		u++;
	//		RESET_LED();
			
				Select_LED(u);
				delay_ms(1000);
				u++;
				RESET_LED();
		//	if(u==10)
		//	{
			//	u=0;
			//	TIM_Cmd(TIM3, DISABLE);
			//}
		}
}





 int main(void)
 {	
	int i=0,t=0;	  
	delay_init();	    	 //延时函数初始化	  
	LED_Init();		  	 	//初始化与LED连接的硬件接口
	KEY_Init();	 //初始化与按键连接的硬件接口
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//	 TIM3_Int_Init(4999,7199);
	 RESET_LED();
	Light_0();
	PAout(8)=0;
	 PDout(2)=1;
	while(1)
	{
		t=KEY_Scan(0);		//得到键值
		switch(t)
		{				 
			case KEY0_PRES:
				RESET_LED();
				i++;
			if(i==10) i=0;
				Select_LED(i);
				break;
			case KEY1_PRES:
				RESET_LED();
				i--;
			if(i==-1) i=9;
				Select_LED(i);
				break;
			case WKUP_PRES:
				RESET_LED();
				TIM3_Int_Init(4999,7199);
				break;
			default:
				delay_ms(10);	
		} 
	}		 
}

博主比较懒啊,所以就把所有的函数都堆到一起了(确实有点过分啊)。都是为了方便啊,我觉得也挺好理解的。

寄存器版
led.c

#include "led.h"

void LED_Init(void)
{
	RCC->APB2ENR|=1<<3;
	GPIOB->CRL&=0xFF0FFFFF;
	GPIOB->CRL|=0x00300000;
	GPIOB->ODR|=1<<5;
	GPIOB->CRL&=0xF0FFFFFF;
	GPIOB->CRL|=0x03000000;
	GPIOB->ODR|=1<<6;
	GPIOB->CRL&=0x0FFFFFFF;
	GPIOB->CRL|=0x30000000;
	GPIOB->ODR|=1<<7;
	
	
	GPIOB->CRH&=0xFFFFFFF0;
	GPIOB->CRH|=0x00000003;
	GPIOB->ODR|=1<<8;
	GPIOB->CRH&=0xFFFFFF0F;
	GPIOB->CRH|=0x00000030;
	GPIOB->ODR|=1<<9;
	GPIOB->CRH&=0xFFFFF0FF;
	GPIOB->CRH|=0x00000300;
	GPIOB->ODR|=1<<10;
	GPIOB->CRH&=0xFFFF0FFF;
	GPIOB->CRH|=0x00003000;
	GPIOB->ODR|=1<<11;
	GPIOB->CRH&=0xFFF0FFFF;
	GPIOB->CRH|=0x00030000;
	GPIOB->ODR|=1<<12;
		
}

key.c

#include "key.h"
#include "delay.h"

void KEY_Init(void)
{
	RCC->APB2ENR|=1<<2;
	RCC->APB2ENR|=1<<4;
	JTAG_Set(SWD_ENABLE);
	
	GPIOA->CRL&=0xFFFFFFF0;
	GPIOA->CRL|=0x00000008;
	
	GPIOA->CRH&=0x0FFFFFFF;
	GPIOA->CRH|=0x80000000;
	GPIOA->ODR|=1<<15;
	
	
	GPIOC->CRL&=0xFF0FFFFF;
	GPIOC->CRL|=0x00800000;
	GPIOC->ODR|=1<<5;
	

}

u8 KEY_Scan(u8 mode)
{
	static u8 key_up=1;
	if(mode) key_up=1;
	if(key_up&&(KEY0==0||KEY1==0||WK_UP==1))
	{
		delay_ms(20);
		key_up=0;
		if(KEY0==0) return KEY0_PRES;
		if(KEY1==0) return KEY1_PRES;
		if(WK_UP==1) return WKUP_PRES;
	}else if(KEY0==1&&KEY1==1&&WK_UP==0) key_up=1;
	return 0;	
}

当然这个代码还有很大的缺陷,比如第三个功能,它虽然可以不断地向上显示数字,但是在向上显示数字的过程中,我却无法让它停止,即就是在此期间按其他按键没有反应。那么问题来了,怎样退出定时器中断呢。学姐给我的建议是让我在按下某个按键后,让这个定时器失能从而实现退出。但是程序在执行的过程中是非常快的,我无法在那一瞬间按下按键,所以这个方法应该是不可行的(当然还有其他可以执行的方法)。

所以到底可以用什么方法呢,我现在还是没搞清楚,希望大家可以多多评论交流啊。

还有,这是我的数码管·==· 嘿嘿
stm32学习笔记(7)数码管显示_第2张图片

你可能感兴趣的:(stm32,stm32基础)