一、項(xiàng)目介紹
串行通信是一種常見的數(shù)據(jù)傳輸方式,允許將數(shù)據(jù)以比特流的形式在發(fā)送端和接收端之間傳輸。當(dāng)前實(shí)現(xiàn)基于STC89C52單片機(jī)的串行通信發(fā)射機(jī),通過紅外發(fā)射管和接收頭實(shí)現(xiàn)自定義協(xié)議的數(shù)據(jù)無線傳輸。
二、系統(tǒng)設(shè)計(jì)
2.1 單片機(jī)選擇
在本設(shè)計(jì)中,選擇了STC89C52作為主控芯片。單片機(jī)具有較高的性能和豐富的外設(shè)資源,適合實(shí)現(xiàn)串行通信發(fā)射機(jī)功能。
2.2 矩陣鍵盤
采用4x4的矩陣鍵盤,用于接收用戶輸入的指令。通過掃描矩陣鍵盤的按鍵狀態(tài),可以獲取用戶需要發(fā)送的數(shù)據(jù)。
2.3 紅外發(fā)射管和接收頭
選擇具有較高發(fā)射功率和較長(zhǎng)發(fā)射距離的紅外發(fā)射管,并配合紅外接收頭進(jìn)行數(shù)據(jù)傳輸。當(dāng)紅外接收頭檢測(cè)到紅外光時(shí),輸出低電平;沒有檢測(cè)到紅外光時(shí),輸出高電平。
2.4 矩陣鍵盤掃描
利用矩陣鍵盤的行列掃描原理,實(shí)時(shí)檢測(cè)用戶按鍵狀態(tài),并將按鍵值保存在變量中供后續(xù)使用。
2.5 數(shù)據(jù)轉(zhuǎn)換和紅外發(fā)送
根據(jù)自定義的協(xié)議格式,將用戶按鍵值轉(zhuǎn)換為紅外控制碼。通過IO口驅(qū)動(dòng)紅外發(fā)射管發(fā)送紅外控制碼。
三、協(xié)議的約定
【1】自定義發(fā)送協(xié)議: 自定義發(fā)送協(xié)議需要約定以下內(nèi)容:
- 幀格式:確定每一幀數(shù)據(jù)的起始標(biāo)志、數(shù)據(jù)長(zhǎng)度和校驗(yàn)信息等。常見的幀格式包括起始位、數(shù)據(jù)位、停止位和校驗(yàn)位。
- 數(shù)據(jù)編碼:確定將要發(fā)送的數(shù)據(jù)轉(zhuǎn)換為比特流進(jìn)行傳輸?shù)姆绞健3R姷木幋a方式有Manchester編碼和Pulse-Width Modulation(PWM)編碼。
- 校驗(yàn)機(jī)制:確定是否需要添加校驗(yàn)位,以保證數(shù)據(jù)傳輸?shù)臏?zhǔn)確性和完整性。常見的校驗(yàn)方式有奇偶校驗(yàn)、循環(huán)冗余校驗(yàn)(CRC)等。
例如,可以采用以下的幀格式作為示例:
- 幀頭:起始位,一個(gè)特定的比特用于標(biāo)識(shí)幀的開始。
- 數(shù)據(jù)字段:包含要發(fā)送的數(shù)據(jù)。
- 校驗(yàn)位:用于檢驗(yàn)幀數(shù)據(jù)的準(zhǔn)確性。
- 幀尾:停止位,一個(gè)特定的比特用于標(biāo)識(shí)幀的結(jié)束。
【2】接收原理: 接收端通過紅外接收頭實(shí)現(xiàn)對(duì)發(fā)送端發(fā)送的紅外控制碼的接收和解碼。接收原理包括以下步驟:
- 紅外信號(hào)接收:紅外接收頭接收紅外光,并將接收到的光信號(hào)轉(zhuǎn)換為電流信號(hào)。
- 弱信號(hào)放大:對(duì)接收到的電流信號(hào)進(jìn)行放大,以便進(jìn)行后續(xù)處理。
- 數(shù)據(jù)解碼:根據(jù)約定的幀格式和編碼方式,將接收到的比特流解碼為原始數(shù)據(jù)。
- 校驗(yàn)校準(zhǔn):對(duì)接收到的數(shù)據(jù)進(jìn)行校驗(yàn)和校準(zhǔn),確保數(shù)據(jù)的準(zhǔn)確性。
下面是發(fā)送端和接收端的代碼:
發(fā)送端代碼:
#include <reg52.h>
// 定義紅外發(fā)射管IO口
#define IR_LED P1
// 發(fā)送一幀數(shù)據(jù)
void sendFrame(unsigned char data) {
unsigned char i;
// 發(fā)送起始位
IR_LED = 0;
DelayUs(300);
for (i = 0; i < 8; i++) {
// 發(fā)送數(shù)據(jù)位
IR_LED = data & 0x01;
DelayUs(300);
data >>= 1;
}
// 發(fā)送停止位
IR_LED = 1;
DelayUs(300);
}
// 主函數(shù)
void main() {
unsigned char sendData = 0x55; // 要發(fā)送的數(shù)據(jù)
while (1) {
sendFrame(sendData); // 發(fā)送一幀數(shù)據(jù)
DelayMs(1000);
}
}
接收端代碼:
#include <reg52.h>
// 定義紅外接收頭IO口
#define IR_RECV P2
// 接收一幀數(shù)據(jù)
unsigned char receiveFrame() {
unsigned char i;
unsigned char data = 0;
while (IR_RECV); // 等待起始位
DelayUs(150);
for (i = 0; i < 8; i++) {
DelayUs(300);
data >>= 1;
if (IR_RECV) {
data |= 0x80;
}
}
return data;
}
// 主函數(shù)
void main() {
unsigned char receivedData;
while (1) {
receivedData = receiveFrame(); // 接收一幀數(shù)據(jù)
// 處理接收到的數(shù)據(jù)
}
}
四、代碼實(shí)現(xiàn)
下面是基于STC89C52單片機(jī)的串行通信發(fā)射機(jī)和接收機(jī)的整體代碼,其中包括了4x4矩陣鍵盤的讀取和紅外數(shù)據(jù)傳輸?shù)墓δ埽?/p>
發(fā)射機(jī)代碼:
#include <reg52.h>
#define IR_LED P1
#define KEYBOARD P2
// 發(fā)送一幀數(shù)據(jù)
void sendFrame(unsigned char data) {
unsigned char i;
// 發(fā)送起始位
IR_LED = 0;
DelayUs(300);
for (i = 0; i < 8; i++) {
// 發(fā)送數(shù)據(jù)位
IR_LED = data & 0x01;
DelayUs(300);
data >>= 1;
}
// 發(fā)送停止位
IR_LED = 1;
DelayUs(300);
}
// 讀取矩陣鍵盤
unsigned char readKeyboard() {
unsigned char row, col, keyVal;
KEYBOARD = 0xF0; // 設(shè)置行為高電平,列為低電平
if (KEYBOARD != 0xF0) { // 檢測(cè)是否有按鍵按下
keyVal = KEYBOARD;
switch (keyVal) {
case 0xE0: row = 0; break;
case 0xD0: row = 1; break;
case 0xB0: row = 2; break;
case 0x70: row = 3; break;
default: return 0xFF;
}
KEYBOARD = 0x0F; // 設(shè)置列為高電平,行為低電平
keyVal = KEYBOARD;
switch (keyVal) {
case 0x0E: col = 0; break;
case 0x0D: col = 1; break;
case 0x0B: col = 2; break;
case 0x07: col = 3; break;
default: return 0xFF;
}
// 根據(jù)行列計(jì)算鍵值
return 4 * row + col + 1;
}
return 0xFF; // 返回?zé)o效鍵值
}
// 主函數(shù)
void main() {
unsigned char sendData;
while (1) {
sendData = readKeyboard(); // 讀取鍵盤數(shù)據(jù)
if (sendData != 0xFF) {
sendFrame(sendData); // 發(fā)送一幀數(shù)據(jù)
}
}
}
接收機(jī)代碼:
#include <reg52.h>
#define IR_RECV P3
// 接收一幀數(shù)據(jù)
unsigned char receiveFrame() {
unsigned char i;
unsigned char data = 0;
while (IR_RECV); // 等待起始位
DelayUs(150);
for (i = 0; i < 8; i++) {
DelayUs(300);
data >>= 1;
if (IR_RECV) {
data |= 0x80;
}
}
return data;
}
// 主函數(shù)
void main() {
unsigned char receivedData;
while (1) {
receivedData = receiveFrame(); // 接收一幀數(shù)據(jù)
// 處理接收到的數(shù)據(jù)
}
}