十六届蓝桥杯单片机4T积分赛第三期-串口报警系统设计
4T第三周积分赛-串口报警系统设计
·

一、串口通信底层代码
由于本题只需要利用串口发送信息,所以在main.c中不用写串口数据处理函数void UartProc()和串口中断函数,在串口初始化中不用额外添加EA = ES = 1;,只需要重载putchar函数利用printf函数发送数据即可。
uart.c
#include <uart.h>
void Uart1_Init(void) //9600bps@12.000MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x01; //串口1选择定时器2为波特率发生器
AUXR &= 0xFB; //定时器时钟12T模式
T2L = 0xE6; //设置定时初始值
T2H = 0xFF; //设置定时初始值
AUXR |= 0x10; //定时器2开始计时
}
extern char putchar(char ch)
{
SBUF = ch;
while(!TI);
TI = 0;
return ch;
}
二、发送页面

数据输入从右向左推入,看起来很难,实际上做起来也不简单,要实现这个功能需要你对for循环的灵活运用。
下面定义的是输入内容存放的数组和其索引。
pdata u8 Input[7] = {10,10,10,10,10,10,10};
idata u8 InputIndex;
下面的这个for循环要写起来可以一步一步的写,毕竟你没有提前接触过是比较不可能直接写出来的,可以按照以下步骤逐步实现:
/*
*第一步,循环条件选取
*由于输入的内容是和数组索引有关系的,所以循环变量应该和索引有关
*/
for(i = 0; i < InputIndex; i++)
/*
*第二步,根据所选用的循环变量初步实现第一次输入数据的功能
*输入一个数据,索引InputIndex为1
*这个时候要让数码管的最右边等于Input的第1位(Input[0])
*也就是SegBuf[7]=Input[0]
*在for循环中实现:SegBuf[7-i]=Input[i]
*/
for(i = 0; i < InputIndex; i++)
SegBuf[7-i]=Input[i]
/*
*第三步
*当输入两个数据的时候,数码管的第六位存放的是第一次输入的数据
*数码管的第二位存放的是第二次输入的数据
*根据这两个条件对for循环进行完善
*SegBuf[7]=Input[1],SegBuf[6]=Input[0]
*可以得出输入内容数组赋值是和其索引有关的
*[7-i] = Input[InputIndex-i-1];
*/
for(i = 0; i < InputIndex; i++)
SegBuf[7-i] = Input[InputIndex-i-1];
idata u8 SegMode; //0-输入页面 1-报警页面
void SegProc()
{
u8 i;
if(!SegMode)
{
SegBuf[0] = 11;
for(i = 0; i < InputIndex; i++)
SegBuf[7-i] = Input[InputIndex-i-1];
}
}
三、输入数据

void KeyProc()
{
u8 send = 0x00;
u8 i;
KeyVal = KeyDisp();
KeyDown = KeyVal & ~KeyOld;
KeyOld = KeyVal;
switch(KeyDown)
{
case 8://输入数字1
if(!SegMode && InputIndex < 7)
{
Input[InputIndex++] = 1;
}
break;
case 12://输入数字0,要求:第一个输入的数据不能是0
if(!SegMode && InputIndex < 7 && InputIndex > 0)
{
Input[InputIndex++] = 0;
}
break;
}
}
四、发送数据(先不考虑报警功能)


由于串口发送的数据是以ASCLL码的形式发送的,上面存放输入数据的是数组,所以在发送前要将数组的每位数据取出合成一个以二进制(十六进制也行)表示的数据。
这个过程和Led的底层代码一样,代码可以自行推理。
for(i = 0; i < InputIndex; i++)
send |= (Input[i] << (InputIndex-i-1));
void KeyProc()
{
u8 send = 0x00;
u8 i;
KeyVal = KeyDisp();
KeyDown = KeyVal & ~KeyOld;
KeyOld = KeyVal;
switch(KeyDown)
{
case 4:
//处于发送页面
if(!SegMode)
{
if(InputIndex > 0)
{
//数据处理
for(i = 0; i < InputIndex; i++)
send |= (Input[i] << (InputIndex-i-1));
//向串口发送数据
printf("%c",send);
//发送完数据后清空缓存区
memset(Input,10,InputIndex);
InputIndex = 0;
//清空缓存区的瞬间清空数码管
for(i = 1; i < 8; i++)
SegBuf[i] = 10;
}
}
break;
}
}
五、报警处理

数值范围转成十进制就是0 ~ 31,转成十六进制是0x00 ~ 0x1f,0b0111 1111也就是0x7f,所以在串口发送数据前可以加上下面代码:
void KeyProc()
{
//...
switch(KeyDown)
{
case 4:
if(!SegMode)
{
if(InputIndex > 0)
{
//数据处理
for(i = 0; i < InputIndex; i++)
send |= (Input[i] << (InputIndex-i-1));
//报警处理
//0~31 31:0x1f 127:16*7+15
if(send >= 0x00 && send <= 0x1f || send == 0x7f)
SegMode = 1;
//数据发送
else
printf("%c",send);
}
}
else//处于报警页面
SegMode = 0;
//由于串口发送完成和关闭报警页面都需要清空缓存区
//所以可以将清空缓存区放到最后
memset(Input,10,InputIndex);
InputIndex = 0;
for(i = 1; i < 8; i++)
SegBuf[i] = 10;
break;
}
}
void SegProc()
{
u8 i;
if(!SegMode)
{
SegBuf[0] = 11;
for(i = 0; i < InputIndex; i++)
SegBuf[7-i] = Input[InputIndex-i-1];
//如果你在发送串口后不想写清空数码管,写以下代码也可以
// for (; i < 7; i++)
// {
// SegBuf[7-i] = 10;
// }
}
else//报警页面
{
SegBuf[0] = 12;
SegBuf[1] = 12;
SegBuf[2] = 10;
SegBuf[3] = 10;
SegBuf[4] = 10;
SegBuf[5] = 10;
SegBuf[6] = 10;
SegBuf[7] = 10;
}
}
六、完整代码
如果你发现了什么错误或者有什么疑问,请在评论区留言或者私信我,我看到会及时解决。
#include <STC15F2K60S2.H>
#include <string.h>
#include <stdio.h>
#include "Init.h"
#include "Key.h"
#include "Seg.h"
#include "uart.h"
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long int u32;
idata unsigned char Key_Slow; //按键减速变量 10ms
idata unsigned int Seg_Slow; //数码管减速变量 500ms
/*按键*/
idata u8 KeyVal,KeyDown,KeyOld;
pdata u8 Input[7] = {10,10,10,10,10,10,10};
idata u8 InputIndex;
/*数码管*/
idata u8 SegPos;
pdata u8 SegBuf[8] = {10,10,10,10,10,10,10,10};
pdata u8 SegPoint[8] = {0,0,0,0,0,0,0,0};
idata u8 SegMode; //0-输入页面 1-报警页面
void KeyProc()
{
u8 send = 0x00;
u8 i;
if(Key_Slow) return;
Key_Slow = 1; //按键减速
KeyVal = KeyDisp();
KeyDown = KeyVal & ~KeyOld;
KeyOld = KeyVal;
switch(KeyDown)
{
case 4:
if(!SegMode)
{
if(InputIndex > 0)
{
//数据处理
for(i = 0; i < InputIndex; i++)
send |= (Input[i] << (InputIndex-i-1));
//0~31 31:0x1f 127:16*7+15
if(send >= 0x00 && send <= 0x1f || send == 0x7f)
SegMode = 1;
//数据发送
else
printf("%c",send);
}
}
else
SegMode = 0;
memset(Input,10,InputIndex);
InputIndex = 0;
for(i = 1; i < 8; i++)
SegBuf[i] = 10;
break;
case 8://输入数字1
if(!SegMode && InputIndex < 7)
{
Input[InputIndex++] = 1;
}
break;
case 12://输入数字0
if(!SegMode && InputIndex < 7 && InputIndex > 0)
{
Input[InputIndex++] = 0;
}
break;
}
}
void SegProc()
{
u8 i;
if(Seg_Slow) return;
Seg_Slow = 1; //数码管减速
if(!SegMode)
{
SegBuf[0] = 11;
for(i = 0; i < InputIndex; i++)
SegBuf[7-i] = Input[InputIndex-i-1];
// for (; i < 7; i++)
// {
// SegBuf[7-i] = 10;
// }
}
else
{
SegBuf[0] = 12;
SegBuf[1] = 12;
SegBuf[2] = 10;
SegBuf[3] = 10;
SegBuf[4] = 10;
SegBuf[5] = 10;
SegBuf[6] = 10;
SegBuf[7] = 10;
}
}
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 Timer0_Isr(void) interrupt 1
{
if(++Key_Slow == 10) Key_Slow = 0; //按键延迟
if(++Seg_Slow == 100) Seg_Slow = 0; //数码管延迟
if(++SegPos == 8) SegPos = 0;
SegDisp(SegPos,SegBuf[SegPos],SegPoint[SegPos]);
}
void main()
{
SystemInit();
Uart1_Init();
Timer0_Init();
while(1)
{
Key_Proc();
Seg_Proc();
}
}
更多推荐

所有评论(0)