串口通信像是藍橋杯單片機組國賽中一個若隱若現的秘境,總在不經意間為勇者們敞開大門。然而,初次探索這片領域的冒險者,常常會被其神秘莫測的特性所震懾,黯然退場(編不下去了,直接進入正題)。
附件:第十五屆藍橋杯單片機組國賽(串口部分)
一、串口三部曲
1.串口初始化
相關原理:速通串口通信
在STC-ISP中按照以下步驟操作即可
在keil中新建uart.c和uart.h
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開始計時ES = 1; //使能串口1中斷EA = 1;
}extern char putchar(char ch)
{SBUF = ch;while(!TI);TI = 0;return ch;
}
uart.h
#include <STC15F2K60S2.H>
#include <stdio.h>void Uart1_Init();
2.串口中斷
main.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.串口數據處理函數
#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.memcmp
與strcmp
對比接收數據存放數組可以使用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.串口解析"?"
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]
表示當前位置坐標
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
保存。
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-解析yidata 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");elseprintf("Busy");}}elseprintf("Error");memset(uartBuf,0,uartBufIndex);uartBufIndex = 0;}
}