第十五届蓝桥杯单片机国赛-串口解析

串口通信像是蓝桥杯单片机组国赛中一个若隐若现的秘境,总在不经意间为勇者们敞开大门。然而,初次探索这片领域的冒险者,常常会被其神秘莫测的特性所震慑,黯然退场(编不下去了,直接进入正题)。

附件:第十五届蓝桥杯单片机组国赛(串口部分)

一、串口三部曲

1.串口初始化

相关原理:速通串口通信

在STC-ISP中按照以下步骤操作即可

在keil中新建uart.c和uart.h

  • uart.c
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开始计时
	ES = 1;				//使能串口1中断
	EA = 1;
}

extern char putchar(char ch)
{
	SBUF = ch;
	while(!TI);
	TI = 0;
	return ch;
}

uart.h

c 复制代码
#include <STC15F2K60S2.H>
#include <stdio.h>

void Uart1_Init();

2.串口中断

  • main.c
c 复制代码
typedef unsigned char u8;

pdata u8 uartBuf[10] = {0,0,0,0,0,0,0,0,0,0};
idata u8 uartBufIndex;
idata u8 uartTick;
idata bit uartFlag;

void Uart1_Isr(void) interrupt 4
{
	if(RI)
	{
		uartFlag = 1;
		uartTick = 0;
		uartBuf[uartBufIndex++] = SBUF;
		RI = 0;
	}
	if(uartBufIndex > 10)
	{
		uartTick = uartFlag = 0;
		uartBufIndex = 0;
		memset(uartBuf,0,10);
	}
}	

3.串口数据处理函数

c 复制代码
#include <string.h>
#include <stdio.h>
#include <math.h>

void uartProc()
{
	if(!uartBufIndex) return;
	
	if(uartTick >= 10)
	{
		uartTick = uartFlag = 0;
		
		//数据解析
		
		memset(uartBuf,0,uartBufIndex);
		uartBufIndex = 0;
	}
}

void Timer1_Isr(void) interrupt 3
{
	if(uartFlag) 
		uartTick++;
}

二、串口功能-查询设备状态

1.memcmpstrcmp

对比接收数据存放数组可以使用memcmp或者strcmp

  • int memcmp(const void *s1, const void *s2, size_t n)

    比较两个内存区域的前 n 个字节。

  • int strcmp(const char *s1, const char *s2)

    比较两个以\0 结尾的字符串,直到遇到第一个不匹配字符或结束符。

2.运动状态设计

定义idata u8 moveState;表示运动状态:

0-空闲 1-等待 2-运行

3.串口解析"?"

c 复制代码
void uartProc()
{
	if(!uartBufIndex) return;
	
	if(uartTick >= 10)
	{
		uartTick = uartFlag = 0;
		
		//串口解析
		if(strcmp(uartBuf, "?") == 0)
		{
			if(!moveState)			//空闲状态
				printf("Idle");
			else if(moveState == 1) //等待状态
				printf("Wait");
			else					//运行状态
				printf("Busy");
		}
		
		memset(uartBuf,0,uartBufIndex);
		uartBufIndex = 0;
	}
}
  • 空闲状态
  • 运行状态

三、串口功能-查询设备位置

定义idata u16 currentPoint[2]表示当前位置坐标

c 复制代码
void uartProc()
{
	if(!uartBufIndex) return;
	
	if(uartTick >= 10)
	{
		uartTick = uartFlag = 0;
		
		if(strcmp(uartBuf, "?") == 0)
		{
			if(!moveState)					//空闲状态
				printf("Idle");
			else if(moveState == 1) //等待状态
				printf("Wait");
			else									  //运行状态
				printf("Busy");
		}
		else if(strcmp(uartBuf, "#") == 0)
			printf("(%u,%u)",currentPoint[0],currentPoint[1]);
		
		memset(uartBuf,0,uartBufIndex);
		uartBufIndex = 0;
	}
}

四、串口功能-设置目的地坐标

接收坐标,例如(30,40)

数据 数组位置 uartBufIndex
( uartBuf[0] 1
3 uartBuf[1] 2
0 uartBuf[2] 3
, uartBuf[3] 4
4 uartBuf[4] 5
0 uartBuf[5] 6
) uartBuf[6] 7
  • 所以判断两个括号只需判断uartBuf[0]uartBuf[uartBufIndex-1]是否为()即可。
  • 然后再将uartBuf[1]uartBuf[uartBufIndex-2]依次取出(用循环,每次循环取出一位),判断是否为数字(0~9),未碰到时,取出的数据是终点坐标的横坐标,用临时变量x保存,碰到,后,取出的数据是终点坐标的纵坐标,用临时变量y保存。
c 复制代码
pdata u16 pointOver[2] = {0,0};  //终点坐标
idata bit dateFlag; //串口接收坐标标志位

void uartProc()
{
	if(!uartBufIndex) return;
	
	if(uartTick >= 10)
	{
		uartTick = uartFlag = 0;
		
		/*
		if(strcmp(uartBuf, "#") == 0)
			printf("(%u,%u)",currentPoint[0],currentPoint[1]);
		else if(strcmp(uartBuf, "?") == 0)
		{
			if(!moveState)					//空闲状态
				printf("Idle");
			else if(moveState == 1) //等待状态
				printf("Wait");
			else									  //运行状态
				printf("Busy");
		}
		*/
		else if(uartBuf[0] == '(' && uartBuf[uartBufIndex-1] == ')')
		{
			idata u16 x = 0, y = 0;
			idata bit parse = 0; //解析标志位 0-解析x 1-解析y
			idata bit useful = 0;//收到的坐标是否有效 0-有效 1-无效
			idata u8 i;
			for(i = 1; i < uartBufIndex - 1; i++)
			{
				u8 ch = uartBuf[i];
				if(ch >= '0' && ch <= '9')
					!parse ? (x = x * 10 + ch - '0') : (y = y * 10 + ch - '0');
				else if(ch == ',')
					parse = 1;
				else//接收到无效数据
				{
					useful = 1;//收到的坐标无效
					break;//直接退出循环
				}
			}
			if(!useful)//数据有效时才保存坐标
			{
				pointOver[0] = x;
				pointOver[1] = y;
				dateFlag = 1; //收到目的地坐标
				if(!moveState)
					printf("Got it");
				else
					printf("Busy");
			}
		}
		else
			printf("Error");
		
		memset(uartBuf,0,uartBufIndex);
		uartBufIndex = 0;
	}
}
相关推荐
灵犀坠2 小时前
前端面试&项目实战核心知识点总结(Vue3+Pinia+UniApp+Axios)
前端·javascript·css·面试·职场和发展·uni-app·html
宇宙realman_9992 小时前
DSP28335 CPU 定时器深度解析:从原理到实战
单片机·嵌入式硬件
Swift社区3 小时前
LeetCode 440 - 字典序的第 K 小数字
算法·leetcode·职场和发展
小李做物联网3 小时前
6.7基于单片机stm32物联网嵌入式项目程序开发之人脸健康检测系统
stm32·单片机·嵌入式硬件·物联网·计算机外设
一枝小雨3 小时前
9 更进一步的 bootloader 架构设计
stm32·单片机·嵌入式·软件架构·ota·bootloader·aes加密
Jerry丶Li3 小时前
三十七、STM32的SPI
stm32·单片机·嵌入式硬件
CoderYanger3 小时前
A.每日一题——3512. 使数组和能被 K 整除的最少操作次数
java·数据结构·算法·leetcode·职场和发展·1024程序员节
007php0073 小时前
redis缓存功能结合实际项目面试之问题与解析
网络·redis·nginx·缓存·面试·职场和发展·php
一支闲人3 小时前
NRF24L01无线通信模块的快速上手
stm32·单片机·嵌入式硬件·nrf24l01无线通信模块
qq_401700413 小时前
运算放大器电路二、实例分析
单片机·嵌入式硬件