蓝桥杯部分

1.串口底层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <Uart.h>

/* 串口初始化函数 */
void UartInit(void) //9600bps@12.000MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x01; //串口1选择定时器2为波特率发生器
AUXR |= 0x04; //定时器时钟1T模式
T2L = 0xC7; //设置定时初始值
T2H = 0xFE; //设置定时初始值
AUXR |= 0x10; //定时器2开始计时
ES = 1;//允许串口中断
EA = 1;//总中断开启
}

/* 字节发送函数 */
void SendByte(unsigned char dat)
{
SBUF=dat;//将dat数据赋给SBUF,将数据发送出去
while(TI == 0);//等待数据发送
TI = 0;//将发送标志位清零
}

/* 字符串发送函数 */
void Uart_Send_String(unsigned char *dat)
{
while(*dat != '\0')//当字符不为空时,继续发送
SendByte(*dat++);//发送后指针dat加1,指向下一个字节
}

2.单片机发送字符串给上位机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
//头文件引用
#include <Key.h>
#include <Nixie.h>
#include <LED.h>
#include <Init.h>
#include <Uart.h>
#include <INTRINS.H>

unsigned char Nixie_Buf[8]={10,10,10,10,10,10,10,10};//数码管显示数据
unsigned char Nixie_Pos;//数码管数据数组位下标
unsigned char Nixie_Point[8]={0,0,0,0,0,0,0,0};//数码管每一段的“点”数据

unsigned char Key;//键值
unsigned char Key_Up,Key_Down,Key_Val,Key_Old;//按键扫描变量
unsigned char ucLED[8]={0,0,0,0,0,0,0,0};//LED显示数据

unsigned int Nixie_Timer;//数码管定时更新
unsigned int Key_Timer;//按键定时扫描

void Key_Proc(void)//按键检测程序
{
if(Key_Timer) return;//Key_Timer=0时执行下面的语句
Key_Timer=1;
//按键扫描部分//
Key_Val=Key_Read();
Key_Down=Key_Val & (Key_Old ^ Key_Val);
Key_Up=~Key_Val & (Key_Old ^ Key_Val);
Key_Old=Key_Val;
}

void Nixie_Proc(void)//信息处理/显示程序
{
if(Nixie_Timer) return;//Nixie_Timer=0时执行下面的语句
Nixie_Timer=1;
}

void LED_Proc(void)//LED“报警”程序
{

}

void Timer0_Init(void) //1毫秒@12.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //定时器中断0打开
EA = 1; //总中断打开
}

void Delay500ms(void) //@12.000MHz
{
unsigned char data i, j, k;

_nop_();
_nop_();
i = 23;
j = 205;
k = 120;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}

void main()
{
Timer0_Init();//定时器初始化
System_Init();//系统板初始化

Uart1_Init();

Delay500ms();//mark:初始化后若立即发送数据,第一个字节会重复发送,所以先延时500ms,等待UART稳定工作,再发送字符串

Uart1_SendString("Hello UART");//字符串发送数据在开启定时器中断时容易被打断,第一个字节刚好卡在没发完的时刻,造成死循环

while(1)//循环执行任务
{
// Key_Proc();
// Nixie_Proc();
// LED_Proc();
}
}

void Timer0_Server(void) interrupt 1//中断服务程序
{
if(++Nixie_Timer==500){Nixie_Timer=0;}//500ms定时长度
if(++Key_Timer==20){Key_Timer=0;}//20ms定时长度
if(++Nixie_Pos==8){Nixie_Pos=0;}//数码管动态显示
Nixie_Disp(Nixie_Pos,Nixie_Buf[Nixie_Pos],Nixie_Point[Nixie_Pos]);//数码管动态显示
LED_Disp(Nixie_Pos,ucLED[Nixie_Pos]);//LED,一轮即可点亮
}

3.上位机发送字符串给单片机

PS:按键4可发送单片机接收到的字符串给上位机

串口处理模块

1
2
3
4
5
6
7
8
9
void Uart1_Server(void) interrupt 4
{
if(RI==1)
{
Uart_RecData[Uart_RecData_Index]=SBUF;
Uart_RecData_Index++;
RI=0;
}
}

按键程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void Key_Proc(void)//按键检测程序
{
if(Key_Timer) return;//Key_Timer=0时执行下面的语句
Key_Timer=1;
//按键扫描部分//
Key_Val=Key_Read();
Key_Down=Key_Val & (Key_Old ^ Key_Val);
Key_Up=~Key_Val & (Key_Old ^ Key_Val);
Key_Old=Key_Val;

switch(Key_Down)
{
case 4:
Uart_SendDataFlag=1;
ucLED[0]=1;
break;
}

}

中断程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void Uart1_Server(void) interrupt 4
{
if(RI==1)
{
Uart_RecData[Uart_RecData_Index]=SBUF;
Uart_RecData_Index++;
RI=0;
}
}

void Timer0_Server(void) interrupt 1 //中断服务程序
{
if(++Uart_Timer==100){Uart_Timer=0;}
if(++Nixie_Timer==500){Nixie_Timer=0;}//500ms定时长度
if(++Key_Timer==10){Key_Timer=0;}//20ms定时长度
if(++Nixie_Pos==8){Nixie_Pos=0;}//数码管动态显示
Nixie_Disp(Nixie_Pos,Nixie_Buf[Nixie_Pos],Nixie_Point[Nixie_Pos]);//数码管动态显示
LED_Disp(Nixie_Pos,ucLED[Nixie_Pos]);//LED,一轮即可点亮

if(Uart_SendDataFlag==1)
{
Uart_SendDataFlag=0;
Uart1_SendString(Uart_RecData);
}
}

4.上位机发送数据控制单片机LED

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void Uart_Proc()
{
if(Uart_Timer)return;
Uart_Timer=1;

// if(Uart_RecData[Uart_RecData_Index-1]==0x0a && Uart_RecData[Uart_RecData_Index-2]==0x0d) //0x0a-->'\n' 0x0d-->'\r'
// {
// if(Uart_RecData_Index==9 && Uart_RecData[0]=='L' && Uart_RecData[1]=='E' && Uart_RecData[2]=='D' && Uart_RecData[3]=='1' && Uart_RecData[4]=='='&&Uart_RecData[5]=='1')
// {
// ucLED[0]=1;
// }
// }
if(Uart_RecData[Uart_RecData_Index-1]==0x0a && Uart_RecData[Uart_RecData_Index-2]==0x0d)
{
if(Uart_RecData_Index==8 && Uart_RecData[0]=='L' && Uart_RecData[1]=='E' && Uart_RecData[2]=='D' && Uart_RecData[3]=='1' && Uart_RecData[4]=='='&&Uart_RecData[5]=='1')
{
Uart_RecData_Index=0;
ucLED[0]=1;
}
else
{
Uart_RecData_Index=0;
}
}
else
{
Uart_RecData_Index=0;
}
}

2.串口优化

putchar重定向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 串口初始化函数 */
void UartInit(void) //9600bps@12.000MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x01; //串口1选择定时器2为波特率发生器
AUXR |= 0x04; //定时器时钟1T模式
T2L = 0xC7; //设置定时初始值
T2H = 0xFE; //设置定时初始值
AUXR |= 0x10; //定时器2开始计时
ES = 1;//允许串口中断
EA = 1;//总中断开启
}

extern char putchar(char ch)
{
SBUF=ch; ///将dat数据
while(TI==0);
TI=0;
return(ch);
}