AL单片机学习任务2

一.任务介绍

1.运用知识

本次任务运用到的知识有矩阵键盘、定时器、DS1302时钟,附加任务运用到的知识有,点阵屏及串口通信

2.概况

本次任务要求制作一个时钟显示确定时间,并可以通过矩阵键盘来调节时钟显示
附加要求时钟信息通过串口通讯用电脑接收,设计一个闹钟,当闹钟时间到了则让点阵屏闪烁

显示部分:

数字信息的显示用到数码管显示的知识,短横线的闪烁则需要用到定时器模块,以1s为一个周期,按下S8进入显示模式

调节部分:

任务要求按下S8进入调节模式,在这里可以用Mode来判断进入哪个模式
任务要求按下S1 5 2 6 3 7进行对时间的加减,并要求按下时对应位进行闪烁,然后通过对应按键对时间进行加减

串口传输:

将每一次变化的信息都传入串口助手中,则可以定义一个变量,将当前时间赋值给它,当不等的时候输出信息,然后在将当前时间赋值给它,任务中我设置了按下按键K1对串口传输的开关。
有问题的是,在文本模式中,输出的信息是以ASCLL码转换,因此需要稍稍处理才能达到理想结果
在这里插入图片描述

闹钟:

设置个条件判断即可,但是因为引脚冲突,会产生原时钟显示不正常的现象,但是起到闹钟作用即可

二.程序源码

1.主文件

main.c

#include <REGX52.H>
#include "Delay.h"
#include "Timer.h"
#include "Keyscan.h"
#include "DS1302.h"
#include "Nixie.h"
#include "Uart.h"
#include "MatrixLED.h"

unsigned char KeyNum,Select,Mode,flag1,flag2,flag3,flag4;

void ShowTime(){
		DS1302_ReadTime();
		Nixie(1,DS1302_Time[3]/10);
		Nixie(2,DS1302_Time[3]%10);
		if(flag1){		//短横线闪烁
			Nixie(3,11);
			Nixie(6,11);
		}else{
			Nixie(3,12);
			Nixie(6,12);
		}
		Nixie(4,DS1302_Time[4]/10);
		Nixie(5,DS1302_Time[4]%10);
		Nixie(7,DS1302_Time[5]/10);
		Nixie(8,DS1302_Time[5]%10);
}

void SetTime(){
	if(Select==0){		//进入该模式全部不动
	Nixie(1,DS1302_Time[3]/10);
	Nixie(2,DS1302_Time[3]%10);
	Nixie(3,11);
	Nixie(6,11);
	Nixie(4,DS1302_Time[4]/10);
	Nixie(5,DS1302_Time[4]%10);
	Nixie(7,DS1302_Time[5]/10);
	Nixie(8,DS1302_Time[5]%10);
	}
	if(KeyNum==1||KeyNum==5) Select=3;		//调节时
	if(Select==3){
		if(Select==3&&flag2){Nixie(1,DS1302_Time[3]/10);Nixie(2,DS1302_Time[3]%10);}		//时闪烁
		Nixie(4,DS1302_Time[4]/10);
		Nixie(5,DS1302_Time[4]%10);
		Nixie(7,DS1302_Time[5]/10);
		Nixie(8,DS1302_Time[5]%10);
		Nixie(3,11);
		Nixie(6,11);
		//调节时加减及越界判断
		if(KeyNum==1){
			DS1302_Time[Select]++;
			if (DS1302_Time[3] > 23) DS1302_Time[3] = 0;
		}
		else if(KeyNum==5){
			DS1302_Time[Select]--;
			if (DS1302_Time[3] < 0) DS1302_Time[3] = 23;
		}
	}
	if(KeyNum==2||KeyNum==6) Select=4;		//调节分
	if(Select==4){
		if(Select==4&&flag2){Nixie(4,DS1302_Time[4]/10);Nixie(5,DS1302_Time[4]%10);}		//分闪烁
		Nixie(1,DS1302_Time[3]/10);
		Nixie(2,DS1302_Time[3]%10);
		Nixie(7,DS1302_Time[5]/10);
		Nixie(8,DS1302_Time[5]%10);
		Nixie(3,11);
		Nixie(6,11);
		//调节分加减及越界判断
		if(KeyNum==2){
			DS1302_Time[Select]++;
			if (DS1302_Time[4] > 59) DS1302_Time[4] = 0;
		}
		else if(KeyNum==6){
			DS1302_Time[Select]--;
			if (DS1302_Time[4] < 0) DS1302_Time[4] = 59;
		}
	}
	if(KeyNum==3||KeyNum==7) Select=5;		//调节秒
	if(Select==5){
		if(Select==5&&flag2){Nixie(7,DS1302_Time[5]/10);Nixie(8,DS1302_Time[5]%10);}		//秒闪烁
		Nixie(4,DS1302_Time[4]/10);
		Nixie(5,DS1302_Time[4]%10);
		Nixie(1,DS1302_Time[3]/10);
		Nixie(2,DS1302_Time[3]%10);
		Nixie(3,11);
	  Nixie(6,11);
		//调节秒加减及越界判断
		if(KeyNum==3){
			DS1302_Time[Select]++;
			if (DS1302_Time[5] > 59) DS1302_Time[5] = 0;
		}
		else if(KeyNum==7){
			DS1302_Time[Select]--;
			if (DS1302_Time[5] < 0) DS1302_Time[5] = 59;
		}
	}
}

void main(){
	//时钟	定时器	串口初始化
	DS1302_Init();
	Timer0_Init();
	Uart1_Init();
	//设置时间
	DS1302_SetTime();
	while(1){
		KeyNum=Key();		//读取按键
		if(KeyNum==8) {Mode=0;Select=0;DS1302_SetTime();}
		else if(KeyNum==4) {Mode=1;}
	switch(Mode){			//模式选择
		case 0:ShowTime();break;
		case 1:SetTime();break;
		}
	if(KeyNum==17) flag4=~flag4;
	if(flag4){				//通过串口将信息传给电脑,可通过K1进行开启和关闭
		if(flag3!=DS1302_Time[5]){		
			unsigned char i;
			for(i=3;i<6;i++){
				if(DS1302_Time[i]>=0&&DS1302_Time[i]<10){
					Uart1_SendByte(48);
					Uart1_SendByte(DS1302_Time[i]+48);
					if(i==3||i==4) Uart1_SendByte(58);
				}
				if(DS1302_Time[i]>9){
					Uart1_SendByte(DS1302_Time[i]/10+48);
					Uart1_SendByte(DS1302_Time[i]%10+48);
					if(i==3||i==4) Uart1_SendByte(58);
				}
			}
			flag3=DS1302_Time[5];
		}
	}
	
	if(DS1302_Time[3]==11&&DS1302_Time[4]==45&&DS1302_Time[5]==14){		//设置闹钟,时间是11:45:14
		unsigned char j;
		for(j=0;j<8;j++){
			MatrixLED_Show(j,0xFF);
		}
	}
	}
}

void Timer0_Routine() interrupt 1
{
	static unsigned int T0count; 
	TL0 = 0x66;
	TH0 = 0xFC;
	T0count++;
	if(T0count>=500){
		T0count=0;
		if(Mode==0) flag1=!flag1;		//控制显示模式短横线闪烁
		if(Mode==1) flag2=!flag2;		//控制调节模式数字闪烁
	}
}

2.相关模块

1.Delay.c

#include <INTRINS.H>
void Delay(unsigned int ms)	//@11.0592MHz
{
	unsigned char data i, j;
	while(ms--){
		_nop_();
		i = 2;
		j = 199;
		do
		{
			while (--j);
		} while (--i);
	}
}

2.Timer.c

#include <REGX52.H>
//定时器0配置
void Timer0_Init(void)		//1毫秒@11.0592MHz
{
	TMOD &= 0xF0;			//设置定时器模式
	TMOD |= 0x01;			//设置定时器模式
	TL0 = 0x66;				//设置定时初始值
	TH0 = 0xFC;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
	ET0=1; 
	EA=1;
	PT0=0;
}
/*void Timer0_Routine() interrupt 1
{
	static unsigned int T0count; 
	TL0 = 0x66;
	TH0 = 0xFC;
	T0count++;
	if(T0count>=){   
		T0count=0;
		}
}
*/



//定时器1配置
void Timer1_Init(void)		//1毫秒@11.0592MHz
{
	TMOD &= 0x0F;			//设置定时器模式
	TMOD |= 0x10;			//设置定时器模式
	TL1 = 0x66;				//设置定时初始值
	TH1 = 0xFC;				//设置定时初始值
	TF1 = 0;				//清除TF1标志
	TR1 = 1;				//定时器1开始计时
	ET1=1; 
	EA=1;
	PT0=0;
}

/*
void Timer1_Routine() interrupt 3
{
	static unsigned int T1count;
	TL1 = 0x66;				
	TH1 = 0xFC;				
	T1count++;
	if(T1count>=){
		}
	}
*/

3.Keyscan.c

#include <REGX52.H>
#include "Delay.h"

/**
  * @brief  矩阵键盘、独立按键读取按键键码,矩阵键盘范围为1~16,独立按键范围为17~20
  * @param  无
  * @retval KeyNumber 按下按键的键码值
			如果按键按下不放,程序会停留在此函数,松手的一瞬间,返回按键键码,没有按键按下时,返回0
  */
unsigned char Key()
{
	unsigned char KeyNumber=0;
	
	P1=0xFF;
	P1_3=0;
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;}
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=5;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=9;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=13;}
	
	P1=0xFF;
	P1_2=0;
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=2;}
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=6;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=10;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=14;}
	
	P1=0xFF;
	P1_1=0;
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=3;}
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=7;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=11;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=15;}
	
	P1=0xFF;
	P1_0=0;
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=4;}
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=8;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=12;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=16;}
	
	if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=17;}
	if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=18;}
	if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=19;}
	if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=20;}
	return KeyNumber;
}

4.DS1302.c

#include <REGX52.H>

sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;

#define DS1302_SECOND		0x80
#define DS1302_MINUTE		0x82
#define DS1302_HOUR			0x84
#define DS1302_DATE			0x86
#define DS1302_MONTH		0x88
#define DS1302_YEAR			0x8C
#define DS1302_DAY			0x8A
#define DS1302_WP				0x8E

char DS1302_Time[]={23,12,12,12,0,0,2};
//年月日时分秒,星期,写保护
unsigned char DS1302_Parameter[]={DS1302_YEAR,DS1302_MONTH,DS1302_DATE,DS1302_HOUR,DS1302_MINUTE,DS1302_SECOND,DS1302_DAY,DS1302_WP};

/**
  * @brief DS1302初始化
  * @param 无
  * @retval 无
  */
void DS1302_Init(){DS1302_CE=0;DS1302_SCLK=0;}

/**
  * @brief 写入一个字节
  * @param Command 命令标识,用于判断写入的地址
					 Data 写入的字节
  * @retval 无
  */
void DS1302_WriteByte(unsigned char Command,unsigned char Data){
	unsigned char i;
	DS1302_CE=1;
	for(i=0;i<8;i++){
		DS1302_IO=Command&(0x01<<i);
		DS1302_SCLK=1;
		DS1302_SCLK=0;
	}
	for(i=0;i<8;i++){
		DS1302_IO=Data&(0x01<<i);
		DS1302_SCLK=1;
		DS1302_SCLK=0;
	}
	DS1302_CE=0;
}

/**
  * @brief 读取一个字节
  * @param Command命令标识
  * @retval 读取出的字节
  */
unsigned char DS1302_ReadByte(unsigned char Command){
	unsigned char i,Data=0x00;
	Command|=0x01;
	DS1302_CE=1;
	for(i=0;i<8;i++){
		DS1302_IO=Command&(0x01<<i);
		DS1302_SCLK=0;
		DS1302_SCLK=1;
	}
	for(i=0;i<8;i++){
		DS1302_SCLK=1;
		DS1302_SCLK=0;
		if(DS1302_IO){Data|=(0x01<<i);}
	}
	DS1302_CE=0;
	DS1302_IO=0;
	return Data;
}

/**
  * @brief	BCD码转换
	* @param	Mod 转为()进制 10为转换为十进制,16为转换为16进制
						Data 需要转换的数据
  * @retval	转换后的结果
  */
unsigned char BCD_Transform(unsigned char Mod,unsigned char Data){
	if(Mod==10){Data=Data/16*10+Data%16;}
	if(Mod==16){Data=Data/10*16+Data%10;}
	return Data;
}

/**
  * @brief 设置时间
  * @param 无
  * @retval 无
  */
void DS1302_SetTime(){
	unsigned char i;
	DS1302_WriteByte(DS1302_Parameter[7],0x00);
	for(i=0;i<7;i++){
		DS1302_WriteByte(DS1302_Parameter[i],BCD_Transform(16,DS1302_Time[i]));
	}
	DS1302_WriteByte(DS1302_Parameter[7],0x80);

}

/**
  * @brief 写入时间
  * @param 无
  * @retval 无
  */
void DS1302_ReadTime(){
	unsigned char i;
	for(i=0;i<7;i++){
		DS1302_Time[i]=BCD_Transform(10,DS1302_ReadByte(DS1302_Parameter[i]));
	}
}

5.Nixie.c

#include <REGX52.H>
#include "Delay.h"

//10是U,11是-,12是不显示
unsigned char Nixie_arr[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x3E,0x40,0x00};

//数码管显示
void Nixie(unsigned char location, num){
	switch(location){
		case 1:P2_4=1;P2_3=1;P2_2=1;break;
		case 2:P2_4=1;P2_3=1;P2_2=0;break;
		case 3:P2_4=1;P2_3=0;P2_2=1;break;
		case 4:P2_4=1;P2_3=0;P2_2=0;break;
		case 5:P2_4=0;P2_3=1;P2_2=1;break;
		case 6:P2_4=0;P2_3=1;P2_2=0;break;
		case 7:P2_4=0;P2_3=0;P2_2=1;break;
		case 8:P2_4=0;P2_3=0;P2_2=0;break;
	}
	P0=Nixie_arr[num];
	//消影
	Delay(1);
	P0=0x00;
}

6.Uart.c

#include <REGX52.H>
#include "DS1302.h"
/**
  * @brief 串口初始化 //4800bps@11.0592MHz
  * @param 无
  * @retval 无
  */
void Uart1_Init(void)	
{
	PCON |= 0x80;		//使能波特率倍速位SMOD
	SCON = 0x40;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xF4;			//设置定时初始值
	TH1 = 0xF4;			//设置定时重载值
	ET1 = 0;			//禁止定时器中断
	TR1 = 1;			//定时器1开始计时
}
/**
  * @brief 串口发送一个字节数据
  * @param Byte 要发送的字节数据
  * @retval 无
  */

void Uart1_SendByte(unsigned char Byte){
	SBUF=Byte;
	while(TI==0);
	TI=0;
}

7.MatrixLED.c

#include <REGX52.H>
#include "Delay.h"
sbit RCLK_=P3^5;
sbit SRCLK_=P3^6;
sbit SER_=P3^4;

#define MATRIX_LED_PORT			P0

/**
  * @brief 点阵屏初始化
  * @param 无
  * @retval 无
  */
void Matrix_Init(){RCLK_=0;SRCLK_=0;}

/**
  * @brief 74HC595写入一个字节
  * @param Byte 写入的字节
  * @retval 无
  */
void _74HC595_WriteByte(unsigned char Byte)
{
	unsigned char i;
	for(i=0;i<8;i++){
		SER_=Byte&(0x80>>i);  //读位
		SRCLK_=1;  //移位
		SRCLK_=0;
	}
	RCLK_=1;  //锁存
	RCLK_=0;
}

/**
  * @brief LED点阵屏显示一列数据
	* @param column 要选择的列,范围:0~7 
					 Data 选择列显示的数据,高位在上,1为亮0为灭
  * @retval
  */
void MatrixLED_Show(unsigned char column,Data){
	_74HC595_WriteByte(Data);
	MATRIX_LED_PORT=~(0x80>>column);
	Delay(1);
	MATRIX_LED_PORT=0xFF;
}
  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值