单片机时钟和闹钟设置,串口通信

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

CMS80F251xEVB使用


前言

EVB板c51程序


一、LCD默认进入时钟模式,P50按键按下一次进入闹钟模式,再按一次退出闹钟模式

二、P20按两次,选中分钟,再按一次,分钟加一,再按两次,选中秒钟,按一次,秒钟加一

三、时钟等于闹钟,D2灯亮灭三次,这时P20按一次,闹钟清零

四、P50按两次,进入串口模式

代码如下:

#include "dis_timer.h"
#define KEY1_STATE_0 0
#define KEY1_STATE_1 1
#define KEY1_STATE_2 2
#define KEY1_STATE_3 3

#define KEY2_STATE_0 0
#define KEY2_STATE_1 1
#define KEY2_STATE_2 2
#define KEY2_STATE_3 3

#define SINGLE_KEY1_TIME 1  //10ms
#define KEY1_INTERVAL 30 //300ms

#define SINGLE_KEY2_TIME 1
#define KEY2_INTERVAL 30

#define KEY1_NONE   0 //
#define KEY1_SHORT  1 //单击
#define KEY1_DOUBLE 2 //双击

#define KEY2_NONE		 0
#define KEY2_SHORT 	 1
#define KEY2_DOUBLE  2
unsigned char leddata[16][2]={{0x07,0x0d},{0x00,0x05},{0x05,0x0b},{0x01,0x0f},{0x02,0x07},{0x03,0x0e},{0x07,0x0e},{0x01,0x05},{0x07,0x0f},{0x03,0x0f},{0x07,0x07},{0x06,0x0e},{0x07,0x08},{0x04,0x0f},{0x07,0x0a},{0x07,0x02}};
unsigned char leddata1[10][2]={{0x0f,0x0d},{0x08,0x05},{0x0d,0x0b},{0x09,0x0f},{0x0a,0x07},{0x0b,0x0e},{0x0a,0x0e},{0x09,0x05},{0x0a,0x0f},{0x0b,0x0f}};
unsigned char dat[4]={0x89,0xAB,0xCD,0xEF};
int flag=0,flag1=0,flag2=0,flag3=0,flag4=0,flag5=0,flag6=0,min_sec;
unsigned char P20_KeyValue,P20_KeyValue1,P50_KeyValue;
unsigned char P20_flag_10ms_key,P20_flag_10ms_key1,P50_flag_10ms_key;
unsigned int s1,s2,s3,s4,ss3=0,ss4=0,ss1=0,ss2=0;
unsigned int we,i,time=0,time1,time2,t1,t2,t3,temp,temp1,temp2;


//***************************************************//
//************Config************//
//***************************************************//
void UART0_Config(void)
{ 
	BRTCON=0X80;	//BRT使能;
	BRTDL=0x64;//计数器初值,65380,波特率9600;
	BRTDH=0xff;	
	FUNCCR=0x05; //UART0,BRT溢出时钟
	SCON0=0X70; //多机控制,接受使能,8位异步模式
	PCON=0X80;//波特率加倍
	PS_RXD0=0X25;//P25作为引脚RX
	P25CFG=0X02;//P25 RX功能
	P24CFG=0X02;//P24 TXD0功能
  ES0=1;//允许中断
//	uint16_t  BRTValue = 0;
//	 uint32_t  BaudRateVlue = 9600;
//	 
//	
//	// (1)设置UARTx的运行模式
//	 
//	 UART_ConfigRunMode(UART0,UART_MOD_ASY_8BIT, UART_BAUD_BRT);
//	 UART_EnableReceive(UART0);
//	 
//	 //(2)配置UARTx的波特率
//	 
//	 UART_ConfigBRTClk(BRT_CLK_DIV_1);	
//	
//	 UART_EnableDoubleFrequency(UART0); 							/*波特率使能倍频:SMOD =1*/
//	
//  #ifdef USE_FORMULA			//使用公式计算定时器的加载值(需要对Systemclock赋值(main.c)),USE_FORMULA 在 选项Option->C51->Preporcessor Symbols->Define中定义
//	 BRTValue = UART_ConfigBaudRate(UART0, BaudRateVlue) ;
//  #else 
//	 BRTValue = 65380; 				//使用数据手册上推荐的加载值(BRT章节)
//  #endif
// 
//	 UART_ConfigBRTPeriod(BRTValue);							/*配置重装值*/
//	 UART_EnableBRT();										/*使能定时器*/
//	 
//	 //(3)配置IO口

//	 GPIO_SET_MUX_MODE(P24CFG,GPIO_P24_MUX_TXD0);			/*TXD0*/
//	 GPIO_SET_MUX_MODE(P25CFG,GPIO_P25_MUX_RXD0);	 		/*RXD0*/
//	 GPIO_SET_PS_MODE(PS_RXD0, GPIO_P25);					/*RXD0输入选择P25*/
//	
//	// (4)设置UART中断
//	
//	// UART_EnableInt(UART0);
//	// IRQ_SET_PRIORITY(IRQ_UART0,IRQ_PRIORITY_LOW);
}

void GPIO_Config(void)
{
	GPIO_SET_MUX_MODE(P50CFG, GPIO_MUX_GPIO);			
	GPIO_ENABLE_INPUT(P5TRIS, GPIO_PIN_0);				
	
	GPIO_SET_MUX_MODE(P20CFG, GPIO_MUX_GPIO);			
	GPIO_ENABLE_INPUT(P2TRIS, GPIO_PIN_0);				
	GPIO_ENABLE_UP(P2UP, GPIO_PIN_0);
	
	GPIO_SET_MUX_MODE(P21CFG, GPIO_MUX_GPIO);			
	GPIO_ENABLE_OUTPUT(P2TRIS,GPIO_PIN_1);				
	GPIO_ENABLE_UP(P2UP, GPIO_PIN_1);             
	
	GPIO_SET_MUX_MODE(P22CFG, GPIO_MUX_GPIO);			
	GPIO_ENABLE_OUTPUT(P2TRIS,GPIO_PIN_2);				
	GPIO_ENABLE_UP(P2UP, GPIO_PIN_2);
}

void TMR0_Config(void)//开定时器0中断
{
	/*
	(1)设置Timer的运行模式
	*/
	TMR_ConfigRunMode(TMR0, TMR_MODE_TIMING,TMR_TIM_16BIT);	
	/*
	(2)设置Timer 运行时钟
	*/
	TMR_ConfigTimerClk(TMR0, TMR_CLK_DIV_12);						/*Fsys = 24Mhz,Ftimer = 2Mhz,Ttmr=0.5us*/
	/*
	(3)设置Timer周期
	*/	
	TMR_ConfigTimerPeriod(TMR0, 45536/256, 45536%256); 				// 20000*0.5us = 10ms,递增计数
		
	/*
	(4)开启中断
	*/
	TMR_EnableOverflowInt(TMR0);

	/*
	(5)设置Timer中断优先级
	*/	
	IRQ_SET_PRIORITY(IRQ_TMR0,IRQ_PRIORITY_LOW);
	IRQ_ALL_ENABLE();	

	/*
	(6)开启Timer
	*/
	TMR_Start(TMR0);
}

void LCD_Config(void)//设置lcd
{
	/*
	(1)设置LED模块运行模式
	*/
	LCD_ConfigRunMode(LCD_DISPLAY_NORMAL);

	
	LCD_ConfigCOMMode( LCD_DUTY_4);		//1/4DUTY
	LCD_ConfigVLCD(LCD_VSEL_VLCD, 15, LCD_BIAS_3);	//VDD =5V, VLcv = 3.3V , 1/3bias

	LCD_ConfigClk(LCD_CLK_FSYS, LCD_CLKDIV_4096);
	LCD_ConfigResistance(LCD_FCMODE_0, LCD_R_60K, LCD_FCCTL_8);
		
	/*
	(2)设置COM口
	*/
	GPIO_SET_MUX_MODE(P00CFG, GPIO_MUX_ANA);	//COM0
	GPIO_SET_MUX_MODE(P01CFG, GPIO_MUX_ANA);	//COM1	
	GPIO_SET_MUX_MODE(P02CFG, GPIO_MUX_ANA);	//COM2
	GPIO_SET_MUX_MODE(P03CFG, GPIO_MUX_ANA);	//COM3	
	
	LCDCOMEN = 0x0f;		//使能COM0~COM3
		
	/*
	(3)设置SEG口
	*/	
	GPIO_SET_MUX_MODE(P04CFG, GPIO_MUX_ANA);	//SEG0	-> 段码屏 SEG0
	GPIO_SET_MUX_MODE(P05CFG, GPIO_MUX_ANA);	//SEG1	-> 段码屏 SEG1
	GPIO_SET_MUX_MODE(P06CFG, GPIO_MUX_ANA);	//SEG2	-> 段码屏 SEG2	
	GPIO_SET_MUX_MODE(P07CFG, GPIO_MUX_ANA);	//SEG3	-> 段码屏 SEG3
	GPIO_SET_MUX_MODE(P10CFG, GPIO_MUX_ANA);	//SEG4	-> 段码屏 SEG4	
	GPIO_SET_MUX_MODE(P11CFG, GPIO_MUX_ANA);	//SEG5	-> 段码屏 SEG5	
	GPIO_SET_MUX_MODE(P12CFG, GPIO_MUX_ANA);	//SEG6	-> 段码屏 SEG6	
	GPIO_SET_MUX_MODE(P13CFG, GPIO_MUX_ANA);	//SEG7	-> 段码屏 SEG7	
	
	LCDSEGEN0 = 0xFF;	//使能SEG8~SEG15	
	
	/*
	(6)设置SEG口数据
	*/
	LCDSEG0 = 0x00;
	LCDSEG1 = 0x00;	
	LCDSEG2 = 0x00;	
	LCDSEG3 = 0x00;
	LCDSEG4 = 0x00;
	LCDSEG5 = 0x00;
	LCDSEG6 = 0x00;
	LCDSEG7 = 0x00;
	/*
	(7)开启LCD
	*/
	LCD_Start();
}









//***************************************************//
//************timer0和串口中断函数************//
//***************************************************//
void Timer0_IRQHandler(void)  interrupt TMR0_VECTOR 
{  
	TMR_ConfigTimerPeriod(TMR0, 45536/256, 45536%256); 				// 20000*0.5us = 10ms,递增计数
	time++;//lcd显示1s递增
  time1++;
	if(time1==50){
		t1=1;     //0.5s标志位,闹钟警报灯亮灭时间
		time1=0;	
	}  
  time2++;
	if(time2==300){
		t2=1;     //3s标志位,发送数据时间
		time2=0;	
	} 
	P20_flag_10ms_key=1; // 置位 10ms 定时标志
	P20_flag_10ms_key1=1; // 置位 10ms 定时标志
	P50_flag_10ms_key=1; // 置位 10ms 定时标志
	for(we=0;we<4;we++){
	 if(we == 0){   
	   LCDSEG6 = leddata[s1][0];
	   LCDSEG7 = leddata[s1][1];
   }
   if(we == 1){  
	   LCDSEG4 = leddata[s2][0];
	   LCDSEG5 = leddata[s2][1];
   }
   if(we == 2){	   
	   LCDSEG2 = leddata[s3][0];	
	   LCDSEG3 = leddata[s3][1];
   }
   if(we == 3){	   
	   LCDSEG0 = leddata1[s4][0];
	   LCDSEG1 = leddata1[s4][1];         
   }		
  }	
		
}


void UART0_IRQHandler(void)  interrupt UART0_VECTOR //串口中断
{
//if(UART_GetSendIntFlag(UART0))
//	{	
//		UART_ClearSendIntFlag(UART0);	
//	}
//	if(UART_GetReceiveIntFlag(UART0))
//	{
//		UART_SendBuff(UART0,UART_GetBuff(UART0));
//		UART_ClearReceiveIntFlag(UART0);	
//	}
	if(RI0==1)
	{
	temp=SBUF0;	//P21=0;
	RI0=0;
	}
}





//***************************************************//
//**********向FPGA发送数据***********//
//***************************************************//
void putschar ()//发送数据
{	
	if(temp==0x11){
		P22=0;t3=1;}
	if(t2&&t3)
		{
	  SBUF0 = dat[i];
		i++;t2=0;
		if(i==4){i=0;}
	  while (!TI0);
	  TI0=0;
	}

}









//***************************************************//
//**************LCD显示功能***************//
//***************************************************//
void LCD_Display()//时钟显示
{ 
	if(time==100){
			s1++;
	    if(s1==10){
		     s1=0;
		     s2++;
		     if(s2==6){
		       s2=0;
		       s3++;
		       if(s3==10){
		          s3=0;
		          s4++;
		          if(s4==6)
		             s4=0;  
		       }}}   
		  time=0; 
		 }
 }



  
void CLOCKINIT()//闹钟初始化显示
{  
	   LCDSEG6 = leddata[ss1][0];LCDSEG7 = leddata[ss1][1];   
	   LCDSEG4 = leddata[ss2][0];LCDSEG5 = leddata[ss2][1];	
     LCDSEG2 = leddata[ss3][0];LCDSEG3 = leddata[ss3][1];     
	   LCDSEG0 = leddata1[ss4][0];LCDSEG1 = leddata1[ss4][1];

}	

void UART()//串口显示收到的数据
{
	
	if(flag6){
     //	putschar(6);
	  //getschar();
		temp1=temp>>4;
		temp2=temp&0x0f;
		LCDSEG0 = leddata[temp1][0];
		LCDSEG1 = leddata[temp1][1];
		LCDSEG2 = leddata[temp2][0];
		LCDSEG3 = leddata[temp2][1];
		LCDSEG6 = 0;
		LCDSEG7 = 0;   
    LCDSEG4 = 0;
		LCDSEG5 = 0;			
	}
}









//***************************************************//
//***************按键读取*******************//
//***************************************************//
unsigned char key1_driver()//P20
{
	static unsigned char  key1_state = 0;//按键状态变量
	static unsigned int key_time  = 0;//按键计时变量
	unsigned char key_return=KEY1_NONE;// 清除 返回按键值
	
	switch(key1_state)
	{
		case KEY1_STATE_0:// 按键状态0:判断有无按键按下
			if(!P20)// 有按键按下
			{
				key_time=0; // 清零时间间隔计数
				key1_state=KEY1_STATE_1;// 然后进入 按键状态1
			}
			break;
		case KEY1_STATE_1: // 按键状态1:软件消抖(确定按键是否有效,而不是误触)。按键有效的定义:按键持续按下超过设定的消抖时间。
			if(!P20)
			{
				key_time++; // 一次10ms
				if(key_time>=SINGLE_KEY1_TIME) // 消抖时间
				{
					key1_state=KEY1_STATE_2;// 如果按键时间超过 消抖时间,即判定为按下的按键有效。按键有效包括两种:单击或者双击,进入按键状态2, 继续判定到底是那种有效按键
				}
			}
			else
				key1_state=KEY1_STATE_0; // 如果按键时间没有超过,判定为误触,按键无效,返回 按键状态0,继续等待按键
			break;
		case KEY2_STATE_2:
			if(P20)
			{
				key_return=KEY1_SHORT;// 返回 有效键值值:单击
				key1_state=KEY1_STATE_0;// 返回 按键状态0,继续等待按键
			}
			break;
			
		default: // 特殊情况:key_state是其他值得情况,清零key_state。
			key1_state=KEY1_STATE_0;
			break;		
		}	
			return key_return;// 返回 按键值
}
unsigned char key1_read()//P20
{
	static unsigned char  key1_state1 = 0;
	static unsigned int key_time1  = 0;	
	unsigned char key_return,key_temp;
	
	key_return=KEY1_NONE;// 清零 返回按键值
	key_temp=key1_driver();// 读取键值
	
	switch (key1_state1)
	{
		case KEY1_STATE_0:// 按键状态0:等待有效按键(通过 key_driver 返回的有效按键值)
			if(key_temp == KEY1_SHORT)  // 如果是[单击],不马上返回单击按键值,先进入 按键状态1,判断是否有[双击]的可能
			{
				key_time1=0; // 清零计时
				key1_state1=KEY1_STATE_1;
			}
			else// 如果不是单击,直接返回按键值。这里的按键值可能是:[双击],[无效按键]
			{
				key_return=key_temp;
			}
			break;
		case KEY1_STATE_1: // 按键状态1:判定是否有[双击]
			if(key_temp == KEY1_SHORT)
			{
				key_return=KEY1_DOUBLE; // 返回 有效按键:[双击]
				key1_state1=KEY1_STATE_0; // 返回 按键状态0,等待新的有效按键
			}
			else
			{
				key_time1++;// 计数 时间间隔
				if(key_time1>=KEY1_INTERVAL) // 超过 时间间隔
			  {
				  key_return=KEY1_SHORT; // 返回 有效按键:[单击]
				  key1_state1=KEY1_STATE_0;// 返回 按键状态0,等待新的有效按键
			  }
			}
			break;		
	}
	return key_return;       // 返回 按键值
}


unsigned char key2_driver()//P50
{
	static unsigned char  key2_state = 0;
	static unsigned int key2_time  = 0;
	unsigned char key2_return=KEY2_NONE;
	
	switch(key2_state)
	{
		case KEY2_STATE_0:
			if(!P50)
			{
				key2_time=0;
				key2_state=KEY2_STATE_1;
			}
			break;
		case KEY2_STATE_1:
			if(!P50)
			{
				key2_time++;
				if(key2_time>=SINGLE_KEY2_TIME)
				{
					key2_state=KEY2_STATE_2;
				}
			}
			else
				key2_state=KEY2_STATE_0;
			break;
		case KEY1_STATE_2:
			if(P50)
			{
				key2_return=KEY2_SHORT;
				key2_state=KEY2_STATE_0;
			}
			break;	
		default:
			key2_state=KEY2_STATE_0;
			break;		
		}	
			return key2_return;
}
unsigned char key2_read()//P50
{
	static unsigned char  key2_state1 = 0;
	static unsigned int key2_time1  = 0;	
	unsigned char key2_return,key2_temp;
	
	key2_return=KEY2_NONE;
	key2_temp=key2_driver();
	
	switch (key2_state1)
	{
		case KEY2_STATE_0:
			if(key2_temp == KEY2_SHORT)
			{
				key2_time1=0;
				key2_state1=KEY2_STATE_1;
			}
			else
			{
				key2_return=key2_temp;
			}
			break;
		case KEY2_STATE_1:
			if(key2_temp == KEY2_SHORT)
			{
				key2_return=KEY2_DOUBLE;
				key2_state1=KEY2_STATE_0;
			}
			else
			{
				key2_time1++;
				if(key2_time1>=KEY2_INTERVAL)
			  {
				  key2_return=KEY2_SHORT;
				  key2_state1=KEY2_STATE_0;
			  }
			}
			break;		
	}
	return key2_return;
}


//***************************************************//
//***************功能实现*************//
//***************************************************//
void CLOCK()//P50进入闹钟模式或者串口模式
{
	if(P50_flag_10ms_key)
	{
		P50_flag_10ms_key = 0;
		P50_KeyValue = key2_read();
		switch(P50_KeyValue)
		{
			case KEY2_SHORT:flag = ~flag;min_sec=0;//进入闹钟模式的标志位
				if(!flag)
				{
					LCD_Display();//返回时钟模式
				}		
			break;
			
			case KEY2_DOUBLE:flag6=~flag6;//进入串口模式的标志位	
			 if(!flag6){
			    LCD_Display();//返回时钟模式
			  }
			break;
		}		
	}	
}

void clock_change()//闹钟设置时间
{
   if(P20_flag_10ms_key && flag)
	{
		CLOCKINIT();
		P20_flag_10ms_key = 0;
		P20_KeyValue=key1_read();
		
		switch(P20_KeyValue)
		{
			case KEY1_DOUBLE:
					min_sec++;
			   
				break;			
			case KEY1_SHORT:
				if(min_sec>0){
				flag2=1;}
				if(min_sec%2==0)
				{ 
					ss3++;
					if(ss3==10)
					{
						ss3=0;
						ss4++;
						if(ss4==6)
						{
							ss4=0;
						}
				 }				
			  }
				if(min_sec%2==1)
				{ 
					ss1++;
					if(ss1==10)
					{
						ss1=0;
						ss2++;
						if(ss2==6)
						{
							ss2=0;
						}	
					}
				}	
				break;		
		 }			 	
  }
	if(flag2){
     	if(ss1==s1&&ss2==s2&&ss3==s3&&ss4==s4){
       flag3=1;}}
}


void clock_warning() //闹钟警报
{   
	if(flag3)//闹钟时间等于时钟时间的标志位
	{ 
			if(t1&&flag1<6)
				{   //0.5秒亮一次或灭一次,flag1闪烁三秒六次的标志位
				      t1=0;
							P21=~P21;
							flag1++;
				}		 
	    clock_reset();		  
		}
}
void clock_reset() //闹钟复位设置
{
	if(P20_flag_10ms_key1)
			 {
				 P20_flag_10ms_key1 = 0;
		     P20_KeyValue1=key1_read();
				 switch(P20_KeyValue1)
		     {
			    case KEY1_SHORT:flag4=1;break;
			   }     
				 if(flag4){
					 ss1=0;ss2=0;ss3=0;ss4=0;flag3=0;flag1=0;flag4=0;flag2=0;min_sec=0;//闹钟清零,警报标志位清零,设置闹钟的按键次数清零
				 }
				
			 }
}
void CLOCK_SET()//时钟模式进入闹钟模式或者串口模式以及返回时钟模式的函数调用
{
	LCD_Display();//时钟模式
	CLOCK();//P50单击进入闹钟显示
	UART();//P50双击进入串口显示
	clock_change();//P20设置闹钟时间
	clock_warning();//闹钟警报以及警报后P20按一次,各标志位清零,闹钟时间清零
}

总结

串口模式可以实现与FPGA的数据收发通信。

posted @ 2022-06-24 08:50  羽小兮  阅读(484)  评论(0)    收藏  举报