单片机时钟和闹钟设置,串口通信
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
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的数据收发通信。

浙公网安备 33010602011771号