基于STM32单片机1602显示电子时钟

1、本系统采用1602显示时分秒,4个按键可以调整时间,一个按键是选择按键,一个按键是加,一个按键是减,一个按键是退出按键。
2、当选择按键按下的时候,该选择位闪烁。
主函数代码:
#include “delay.h”
#include “sys.h”
#include “1602.h”
#include “timer.h”
#include “key.h”
u8 table1[]="liyang " ;
u8 table2[]=“9876543210654321” ;
signed char miao,fen,shi;
u8 flag_100ms=0;
u16 count_ms=0;
u8 S1num;
/主函数*****/
int main(void)
{
//u8 t;
delay_init();//延时函数初始化
LCD1602_Init();//LCD1602初始化函数
TIM3_Int_Init(999,71);//1MS
TIM4_Int_Init(999,71);//1MS
KEY_Init(); //按键初始化
#IF 0 //注释掉程序
LCD_Write_Command(0x80);//第一行的首地址
for(i=0;i<16;i++)
{
LCD_Write_Date(table1);
delay_ms(3);
}
LCD_Write_Command(0xc0);//第二行的首地址
for(i=0;i<16;i++)
{
LCD_Write_Date(table2);
delay_ms(3);
}
#endif
while(1)
{

  display(shi,fen,miao);

keyscan();
}

}
定时器代码
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能

//定时器TIM3初始化
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(TIM3, ENABLE); //使能TIMx
}
//3中断服务程序
void TIM3_IRQHandler(void) //TIM3中断
{
static u16 count=0;
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx更新中断标志
count++;
count_ms++;
if(count_ms500)
{
count_ms=0;
flag_100ms=~flag_100ms;
}
if(count
1000)
{
count=0;
miao++;
if(miao60)
{
miao=0;
fen++;
if(fen
60)
{
fen=0;
shi++;
if(shi==24)
shi=0;
}
}
}

}
}
//通用定时器4中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM4_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //时钟使能

//定时器TIM4初始化
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(TIM4, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位

TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE ); //使能指定的TIM4中断,允许更新中断
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //TIM4中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
TIM_Cmd(TIM4, ENABLE); //使能TIMx
}
//定时器4中断服务程序
void TIM4_IRQHandler(void) //TIM3中断
{
if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否
{
TIM_ClearITPendingBit(TIM4, TIM_IT_Update ); //清除TIMx更新中断标志
count_ms++;
if(count_ms==500)
{
count_ms=0;
flag_100ms=~flag_100ms;
}
}
}
1602代码
#include"1602.h"
#include"sys.h"
#include “delay.h”
extern u8 S1num;
extern u8 flag_100ms;
/LCD1602初始化*****/
void LCD1602_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE|RCC_APB2Periph_GPIOA, ENABLE); //使能PA,PC端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10; //LCD1602的三根控制线rs,rw,en
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_Init(GPIOE, &GPIO_InitStructure);//根据设定参数初始化GPIOE

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;//LCD1602的8跟数据线        //LED1-->PE.5 端口配置, 推挽输出
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//IO口速度为50MHz
 GPIO_Init(GPIOA, &GPIO_InitStructure);//根据设定参数初始化GPIOE
LCD_Write_Command(0x01);//清除屏幕显示
delay_ms(2);

LCD_Write_Command(0x38);//设置LCD两行显示,一个数据由5*7点阵表示,数据由8跟线传输
 delay_ms(2);

LCD_Write_Command(0x06);//设定输入方式,增量不移位
delay_ms(2);
LCD_Write_Command(0x0c);//开整体显示,关光标,不闪烁
delay_ms(2); 

}
/写指令函数*****/
void LCD_Write_Command(u8 com)
{
GPIO_Write(GPIOA, 0X00FF&com);//该函数一般用来往一次性一个GPIO的多个端口设置
rs=0; //写指令函数和写数据函数其实可以并一起价格 BOOL变量判断是写指令就rs=0写数据就rs=1。
rw=0;
en=0; //写指令 输入:RS=L,RW=L,E=下降沿脉冲
delay_ms(2);
en=1;
delay_ms(2);
en=0;
}
/写数据函数*****/
void LCD_Write_Date(u8 date)
{
GPIO_Write(GPIOA,0X00FF&date);//GPIOA的第八位用来作为8位数据口
rs=1;
rw=0;
en=0; //写指令 输入:RS=L,RW=L,E=下降沿脉冲
delay_ms(2);
en=1;
delay_ms(2);
en=0;
}
/******************************************************************************
函数名称:LCD1602_MoveToPosition
函数功能:将液晶的光标移动到指定的位置
入口参数:x-液晶显示的行数,范围0-1
x = 0:在液晶的第一行
x = 1:在液晶的第二行
y-液晶显示的列数,范围0-15
y = 0:在液晶的第一列
y = 1:在液晶的第二列

y = 15:在液晶的第十六列
返回值:无
备注:通过指定x,y的值可以将液晶的光标移动到指定的位置
*/
void LCD1602_MoveToPosition(u8 x,u8 y)
{
if(0 == x)
LCD_Write_Command(0x80 | y); //光标定位到第一行的y列
if(1 == x)
LCD_Write_Command(0xC0 | y); //光标定义到第二行的y列
}
/

函数名称:LCD1602_DisplayOneCharOnAddr
函数功能:在指定的位置上显示指定的字符
入口参数:x-液晶显示的行数,范围0-1
x = 0:在液晶的第一行
x = 1:在液晶的第二行
y-液晶显示的列数,范围0-15
y = 0:在液晶的第一列
y = 1:在液晶的第二列

y = 15:在液晶的第十六列
ucData-要显示的字符数据
返回值:无
备注:确保x,y的取值要在指定的范围内
*/
void LCD1602_DisplayOneCharOnAddr(u8 x,u8 y,u8 ucData)
{
LCD1602_MoveToPosition(x,y); //光标位置
LCD_Write_Date(ucData); //写入数据
}
/

函数名称:LCD1602_DisplayString
函数功能:显示字符串
入口参数:ucStr-字符串的首地址
返回值:无
备注:无
*******************************************************************************/
void LCD1602_DisplayString(u8 ucStr)
{
while(ucStr != ‘\0’) //字符串结束之前,循环显示
{
LCD_Write_Date(ucStr); //依次写入每一个字符
ucStr++; //指针增加
}
}
/控制光标函数
/
void write_guanbiao(u8 hang,u8 add,u8 date)
{
if(hang1)
LCD_Write_Command(0x80+add);
else
LCD_Write_Command(0x80+0x40+add);
if(date == 1)
LCD_Write_Command(0x0f); //显示光标并且闪烁
else
LCD_Write_Command(0x0c); //关闭光标
}
void display(u8 aa,u8 bb,u8 cc)
{
if(S1num!=3)
{
LCD1602_DisplayOneCharOnAddr(1,0,aa/10+0x30);
LCD1602_DisplayOneCharOnAddr(1,1,aa%10+0x30);
}
else
{
if(flag_100ms
0)
{
LCD1602_DisplayOneCharOnAddr(1,0,’ ‘);
LCD1602_DisplayOneCharOnAddr(1,1,’ ');

}
else
{
LCD1602_DisplayOneCharOnAddr(1,0,aa/10+0x30);
LCD1602_DisplayOneCharOnAddr(1,1,aa%10+0x30);
}
}
LCD1602_DisplayOneCharOnAddr(1,2,’:’);
if(S1num!=2)
{
LCD1602_DisplayOneCharOnAddr(1,3,bb/10+0x30);
LCD1602_DisplayOneCharOnAddr(1,4,bb%10+0x30);
}
else
{
if(flag_100ms==0)
{
LCD1602_DisplayOneCharOnAddr(1,3,’ ‘);
LCD1602_DisplayOneCharOnAddr(1,4,’ ');

}
else
{
LCD1602_DisplayOneCharOnAddr(1,3,bb/10+0x30);
LCD1602_DisplayOneCharOnAddr(1,4,bb%10+0x30);
}
}
LCD1602_DisplayOneCharOnAddr(1,5,’:’);
if(S1num!=1)
{
LCD1602_DisplayOneCharOnAddr(1,6,cc/10+0x30);
LCD1602_DisplayOneCharOnAddr(1,7,cc%10+0x30);
}
else
{
if(flag_100ms==0)
{
LCD1602_DisplayOneCharOnAddr(1,6,’ ‘);
LCD1602_DisplayOneCharOnAddr(1,7,’ ');
}
else
{
LCD1602_DisplayOneCharOnAddr(1,6,cc/10+0x30);
LCD1602_DisplayOneCharOnAddr(1,7,cc%10+0x30);
}
}
}

你可能感兴趣的:(stm32)