基于STM32程序万年历液晶1602显示-proteus仿真-源程序

一、系统方案
本设计采用STM32单片机作为主控器,液晶1602显示,按键设置万年历。
基于STM32程序万年历液晶1602显示-proteus仿真-源程序_第1张图片
二、硬件设计
原理图如下:
基于STM32程序万年历液晶1602显示-proteus仿真-源程序_第2张图片
三、单片机软件设计
1、首先是系统初始化
//通用定时器3中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM3_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); //仿真必须加
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能

//定时器TIM3初始化  C 语言结构体Struct、指针*  ->  &、类型定义typedef

TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位

TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断

//中断优先级NVIC设置
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寄存器

// TIM_Cmd(TIM1, ENABLE); //使能TIMx
TIM_Cmd(TIM3, ENABLE); //使能TIMx
}
2、液晶显示程序
void LCD1602_GPIO_Config(void)
{
RCC_APB2PeriphClockCmd(LCD1602_CLK, ENABLE);
GPIO_InitTypeDef LCD1602_GPIOStruct;
LCD1602_GPIOStruct.GPIO_Mode = GPIO_Mode_Out_PP;
LCD1602_GPIOStruct.GPIO_Speed = GPIO_Speed_10MHz;
LCD1602_GPIOStruct.GPIO_Pin = LCD1602_E | LCD1602_RS | LCD1602_RW ;
GPIO_Init(LCD1602_GPIO_PORT,&LCD1602_GPIOStruct);
LCD1602_GPIOStruct.GPIO_Mode = GPIO_Mode_Out_OD;
LCD1602_GPIOStruct.GPIO_Pin = DB0 | DB1 | DB2 |DB3 | DB4 | DB5|
DB6 | DB7 ; //设置为开漏输出
GPIO_Init(LCD1602_GPIO_PORT,&LCD1602_GPIOStruct);
}

void LCD1602_WaitReady(void) //检测忙状态
{
uint8_t sta;

GPIOB->ODR =0x00FF;
RSO(0);
RWO(1);
EO(1);
SysTick_Delay_Us(1);
do{
	sta=GPIO_ReadInputDataBit(LCD1602_GPIO_PORT,GPIO_Pin_7);
	EO(0);
}while(sta);

}

void LCD1602_WriteCmd(uint8_t cmd) //写指令
{
LCD1602_WaitReady();
RSO(0);
RWO(0);
EO(0);
SysTick_Delay_Us(1);
EO(1);
LCD1602_GPIO_PORT->ODR &= (cmd|0xFF00);
EO(0);
SysTick_Delay_Us(400);
}

void LCD1602_WriteDat(uint8_t dat) //写数据
{
LCD1602_WaitReady();
RSO(1);
RWO(0);
SysTick_Delay_Us(30);
EO(1);
LCD1602_GPIO_PORT->ODR &=(dat|0xFF00);
EO(0);
SysTick_Delay_Us(400);
}

3、按键程序
void KEY_Scan( void )
{

 if(KEY1==0)			//读取K1按键状态
	{
		SysTick_Delay_Ms(10);
		if(KEY1==0)
		{
			while(KEY1==0);
		 	KEY_num++;
			 TIM_ITConfig(TIM3,TIM_IT_Update,DISABLE);   //禁止TIM3中断
			TIM_Cmd(TIM3,DISABLE);        
			if( KEY_num >=8 )
			{
				KEY_num = 0;
				
			  TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);//开启定时器
			  TIM_Cmd(TIM3,ENABLE);
			} 
		
		}
	}
	if(KEY2==0)			//读取K2按键状态,加
	{
		SysTick_Delay_Ms(10);
		if(KEY2==0)
		{
			while(KEY2==0);
				if( KEY_num == 1 )
			{
				nian++;
				if( nian > 2999 )
				{
					nian = 0;
				}
			}
			if( KEY_num == 2 )
			{
				yue++;
				if( yue > 12 )
				{
					yue = 1;
				}
			}
			if( KEY_num == 3 )
			{
				ri++;
				if( ri > 30 )
				{
					ri = 1;
				}
			}
			if( KEY_num == 4 )
			{
				shi++;
				if( shi > 23 )
				{
					shi = 0;
				}
			}
			if( KEY_num ==5 )
			{
				fen++;
				if( fen > 59 )
				{
					fen = 0;
				}
			}
			if( KEY_num == 6 )
			{
				miao++;
				if( miao > 59 )
				{
					miao = 0;
				}
			}
			if( KEY_num == 7 )
			{
				week++;
				if( week > 7 )
				{
					week = 1;
				}
			}
			Display_Time();
		
		}
	}
	if(KEY3==0)			//读取K3按键状态,减
	{
		SysTick_Delay_Ms(10);
		if(KEY3==0)
		{
			while(KEY3==0);
		 	if( KEY_num == 1 )
			{
				nian--;
				if( nian < 2000 )
				{
					nian = 2999;
				}
			}
			if( KEY_num == 2 )
			{
				yue--;
				if( yue <= 0 )
				{
					yue = 12;
				}
			}
			if( KEY_num == 3 )
			{
				ri--;
				if( ri <= 0 )
				{
					ri = 30;
				}
			}
			if( KEY_num == 4 )
			{
				shi--;
				if( shi <= 0 )
				{
					shi = 23;
				}
			}
			if( KEY_num == 5 )
			{
				fen--;
				if( fen <= 0 )
				{
					fen = 59;
				}
			}
			if( KEY_num == 6 )
			{
				miao--;
				if( miao <= 0 )
				{
					miao = 59;
				}
			}
			if( KEY_num == 7 )
			{
				week--;
				if( week <= 0 )
				{
					week = 7;
				}
			}
		Display_Time();
		
		}
	}

}
4、核心算法程序
//定时器3中断服务程序
void TIM3_IRQHandler(void) //TIM3中断
{
miao++;
if( miao==60)
{
miao = 0;
fen++;
if( fen 60)
{
fen=0;
shi++;
if( shi
24 )
{
shi = 0;
week++;
if(week>7) week=1;
ri++;
if( ri > 30 )
{
ri = 0;
yue++;
if( yue > 12 )
{
yue = 0;
nian++;
if( nian > 2999 )
{
nian = 0;
}
}
}
}

	}
}

TIM_ClearITPendingBit(TIM3, TIM_IT_Update  ); //TIM_IT_Update=0
//清除TIM3更新中断标志 进中断1(硬件),为保证下次再产生中断软件清中断标志

}
四、 proteus仿真设计
Proteus软件是一款应用比较广泛的工具,它可以在没有硬件平台的基础上通过自身的软件仿真出硬件平台的运行情况,这样就可以通过软件仿真来验证我们设计的方案有没有问题,如果有问题,可以重新选择器件,连接器件,直到达到我们设定的目的,避免我们搭建实物的时候,如果当初选择的方案有问题,我们器件都已经焊接好了,再去卸载下去,再去焊接新的方案的器件,测试,这样会浪费人力和物力,也给开发者带来一定困惑,Proteus仿真软件就很好的解决这个问题,我们在设计之初,就使用该软件进行模拟仿真,测试,选择满足我们设计的最优方案。最后根据测试没问题的仿真图纸,焊接实物,调试,最终完成本设计的作品。
基于STM32程序万年历液晶1602显示-proteus仿真-源程序_第3张图片

你可能感兴趣的:(单片机,嵌入式硬件)