串行通信是一种常见的数据传输方式,允许将数据以比特流的形式在发送端和接收端之间传输。当前实现基于STC89C52单片机的串行通信发射机,通过红外发射管和接收头实现自定义协议的数据无线传输。
在本设计中,选择了STC89C52作为主控芯片。单片机具有较高的性能和丰富的外设资源,适合实现串行通信发射机功能。
采用4x4的矩阵键盘,用于接收用户输入的指令。通过扫描矩阵键盘的按键状态,可以获取用户需要发送的数据。
选择具有较高发射功率和较长发射距离的红外发射管,并配合红外接收头进行数据传输。当红外接收头检测到红外光时,输出低电平;没有检测到红外光时,输出高电平。
利用矩阵键盘的行列扫描原理,实时检测用户按键状态,并将按键值保存在变量中供后续使用。
根据自定义的协议格式,将用户按键值转换为红外控制码。通过IO口驱动红外发射管发送红外控制码。
【1】自定义发送协议: 自定义发送协议需要约定以下内容:
例如,可以采用以下的帧格式作为示例:
【2】接收原理: 接收端通过红外接收头实现对发送端发送的红外控制码的接收和解码。接收原理包括以下步骤:
下面是发送端和接收端的代码:
发送端代码:
- #include <reg52.h>
-
- // 定义红外发射管IO口
- #define IR_LED P1
-
- // 发送一帧数据
- void sendFrame(unsigned char data) {
- unsigned char i;
-
- // 发送起始位
- IR_LED = 0;
- DelayUs(300);
-
- for (i = 0; i < 8; i++) {
- // 发送数据位
- IR_LED = data & 0x01;
- DelayUs(300);
- data >>= 1;
- }
-
- // 发送停止位
- IR_LED = 1;
- DelayUs(300);
- }
-
- // 主函数
- void main() {
- unsigned char sendData = 0x55; // 要发送的数据
-
- while (1) {
- sendFrame(sendData); // 发送一帧数据
- DelayMs(1000);
- }
- }
-
接收端代码:
- #include <reg52.h>
-
- // 定义红外接收头IO口
- #define IR_RECV P2
-
- // 接收一帧数据
- 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;
- }
-
- // 主函数
- void main() {
- unsigned char receivedData;
-
- while (1) {
- receivedData = receiveFrame(); // 接收一帧数据
- // 处理接收到的数据
- }
- }
-
下面是基于STC89C52单片机的串行通信发射机和接收机的整体代码,其中包括了4x4矩阵键盘的读取和红外数据传输的功能:
发射机代码:
- #include <reg52.h>
-
- #define IR_LED P1
- #define KEYBOARD P2
-
- // 发送一帧数据
- void sendFrame(unsigned char data) {
- unsigned char i;
-
- // 发送起始位
- IR_LED = 0;
- DelayUs(300);
-
- for (i = 0; i < 8; i++) {
- // 发送数据位
- IR_LED = data & 0x01;
- DelayUs(300);
- data >>= 1;
- }
-
- // 发送停止位
- IR_LED = 1;
- DelayUs(300);
- }
-
- // 读取矩阵键盘
- unsigned char readKeyboard() {
- unsigned char row, col, keyVal;
-
- KEYBOARD = 0xF0; // 设置行为高电平,列为低电平
-
- if (KEYBOARD != 0xF0) { // 检测是否有按键按下
- 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; // 设置列为高电平,行为低电平
- 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;
- }
-
- // 根据行列计算键值
- return 4 * row + col + 1;
- }
-
- return 0xFF; // 返回无效键值
- }
-
- // 主函数
- void main() {
- unsigned char sendData;
-
- while (1) {
- sendData = readKeyboard(); // 读取键盘数据
- if (sendData != 0xFF) {
- sendFrame(sendData); // 发送一帧数据
- }
- }
- }
-
接收机代码:
- #include <reg52.h>
-
- #define IR_RECV P3
-
- // 接收一帧数据
- 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;
- }
-
- // 主函数
- void main() {
- unsigned char receivedData;
-
- while (1) {
- receivedData = receiveFrame(); // 接收一帧数据
- // 处理接收到的数据
- }
- }
-