2024年10月28日 星期一

請ChatGPT協助除錯ESP8266機智雲的MicroPython程式

一、先給提示詞"修訂程式與並給一個初步程式碼:









 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from machine import Pin
from machine import Timer

# Define led_status as a global variable
led_status = 0

# Initialize LED pin
led = Pin(2, Pin.OUT)

# Define the LED flash function
def flash_led(timer):
    global led_status
    led.value(led_status)
    led_status = 1 - led_status

# Set up a periodic timer to toggle the LED every 500ms
tim = Timer(-1)
tim.init(period=500, mode=Timer.PERIODIC, callback=flash_led)

# No need for a while loop if the timer handles the LED toggling
# Just keep the script alive
while True:
    pass










ChatGPT很快地幫忙找出程式有三項問題,包括:全域變數、計時器的初始化、以及多餘程式碼,並給予正確的程式碼。

二、提示語告訴要產生的程式和使用接腳


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
from machine import Pin, Timer, PWM
import time

# 定義 LED 狀態
led_status = 0

# 初始化 LED 引腳
led = Pin(2, Pin.OUT)

# 定義 PWM 的引腳,使用 GPIO 4
buzzer = PWM(Pin(4))

# 音符對應的頻率(以簡單音階為例)
tones = {
    'C': 261,
    'D': 294,
    'E': 329,
    'F': 349,
    'G': 392,
    'A': 440,
    'B': 493
}

# 播放音符的函數
def play_tone(tone, duration):
    if tone in tones:
        buzzer.freq(tones[tone])  # 設定頻率
        buzzer.duty(512)  # 設定占空比,0-1023 之間,512 表示 50% 占空比
        time.sleep(duration)  # 播放音符的持續時間
        buzzer.duty(0)  # 停止聲音

# 定義 LED 閃爍的函數
def flash_led(timer):
    global led_status
    led.value(led_status)
    led_status = 1 - led_status

# 設置一個定時器,每500毫秒切換 LED 狀態
tim = Timer(-1)
tim.init(period=500, mode=Timer.PERIODIC, callback=flash_led)

# 播放一段簡單音樂的函數
def play_melody():
    melody = ['C', 'D', 'E', 'F', 'G', 'A', 'B', 'C']  # 簡單音階
    duration = 0.5  # 每個音符的持續時間為0.5秒
    for note in melody:
        play_tone(note, duration)
        time.sleep(0.1)  # 音符之間的短暫停頓

# 播放音樂
play_melody()

# 保持程式運行
while True:
    pass



三、請ChatGPT產生機智雲板子上的光敏電阻和LED控制程式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
from machine import Pin, ADC, PWM
import time

# 初始化光敏電阻 (A0)
light_sensor = ADC(0)

# 初始化 RGB LED 引腳
red = PWM(Pin(15), freq=500)
green = PWM(Pin(12), freq=500)
blue = PWM(Pin(13), freq=500)

# 設置初始 LED 亮度
red.duty(0)
green.duty(0)
blue.duty(0)

# 設定光線閾值,低於這個值時視為光線暗,進行顏色變化
LIGHT_THRESHOLD = 500  # 根據實際環境調整

# 顏色變化函數
def set_color(r, g, b):
    red.duty(r)
    green.duty(g)
    blue.duty(b)

# 變化 RGB 顏色
def color_cycle():
    set_color(1023, 0, 0)    # 紅色
    time.sleep(0.5)
    set_color(0, 1023, 0)    # 綠色
    time.sleep(0.5)
    set_color(0, 0, 1023)    # 藍色
    time.sleep(0.5)
    set_color(1023, 1023, 0) # 黃色
    time.sleep(0.5)
    set_color(0, 1023, 1023) # 青色
    time.sleep(0.5)
    set_color(1023, 0, 1023) # 紫色
    time.sleep(0.5)
    set_color(1023, 1023, 1023) # 白色
    time.sleep(0.5)

# 主迴圈
while True:
    light_value = light_sensor.read()  # 讀取光敏電阻的數值
    print("Light Value:", light_value)  # 可在控制台查看光線讀數

    if light_value < LIGHT_THRESHOLD:  # 如果光線低於閾值,啟動 RGB 變化
        color_cycle()
    else:
        # 關閉 RGB LED
        set_color(0, 0, 0)

    time.sleep(1)  # 每秒檢查一次光線狀態



最後把兩支程式請ChatGPT合併後的程式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
from machine import Pin, Timer, PWM, ADC
import time

# 初始化 LED 引腳
led = Pin(2, Pin.OUT)
led_status = 0

# 初始化蜂鳴器的 PWM 引腳,使用 GPIO 4
beeper = PWM(Pin(4, Pin.OUT))

# 初始化光敏電阻 (A0) 和 RGB LED (GPIO 15, 12, 13)
light_sensor = ADC(0)
red = PWM(Pin(15), freq=500)
green = PWM(Pin(12), freq=500)
blue = PWM(Pin(13), freq=500)

# 設置初始 RGB LED 亮度
red.duty(0)
green.duty(0)
blue.duty(0)

# 光線強度閾值,低於此值視為光線暗
LIGHT_THRESHOLD = 500

# 定義 LED 閃爍的函數
def flash_led(timer):
    global led_status
    led.value(led_status)
    led_status = 1 - led_status

# 定義 PWM 控制 RGB 顏色
def set_color(r, g, b):
    red.duty(r)
    green.duty(g)
    blue.duty(b)

# 顏色變化函數
def color_cycle():
    set_color(1023, 0, 0)    # 紅色
    time.sleep(0.5)
    set_color(0, 1023, 0)    # 綠色
    time.sleep(0.5)
    set_color(0, 0, 1023)    # 藍色
    time.sleep(0.5)
    set_color(1023, 1023, 0) # 黃色
    time.sleep(0.5)
    set_color(0, 1023, 1023) # 青色
    time.sleep(0.5)
    set_color(1023, 0, 1023) # 紫色
    time.sleep(0.5)
    set_color(1023, 1023, 1023) # 白色
    time.sleep(0.5)

# 音樂音符和頻率
notes = [
    392, 330, 330, 0, 
    349, 294, 294, 0, 
    262, 294, 330, 349, 392, 392, 392, 0
]

# 音樂播放函數
def play_melody():
    for note in notes:
        if note == 0:
            beeper.duty(0)  # 休止符
        else:
            beeper.duty(512)  # 設置音量
            beeper.freq(note) # 設置頻率
        time.sleep(0.2)  # 音符持續 0.2 秒
        beeper.duty(0)
        time.sleep(0.1)  # 休止 0.1 秒

# 設置一個定時器,每 500 毫秒切換 LED 狀態
tim_led = Timer(-1)
tim_led.init(period=500, mode=Timer.PERIODIC, callback=flash_led)

# 主迴圈
while True:
    # 讀取光敏電阻的數值
    light_value = light_sensor.read()
    print("Light Value:", light_value)

    if light_value < LIGHT_THRESHOLD:  # 如果光線低於閾值,顯示 RGB 顏色變化
        color_cycle()
    else:
        set_color(0, 0, 0)  # 光線充足時,關閉 RGB LED

    play_melody()  # 播放音樂
    time.sleep(2)  # 每隔 2 秒播放一次音樂並檢查光線狀況


2024年10月13日 星期日

[8051 and ESP32 CAM] 實作雙晶片的連線

參考教材1:單晶片微處理機實習,黃嘉輝,台科大出版

參考教材2:使用ESP32開發版與Arduino C程式語言,尤濬哲 ,台科大出版

前一篇文章:[8051] 實作檢查碼,若有錯則顯示錯誤

前幾篇文章都是設定在通訊鮑率為9600bps,但在這一篇我們選擇1200bps,其原因是因為實驗室的實習板是採用12M Hz石英振盪器,您可以參考:8051 Baud Rate Calculator

8051程式碼(新增恢復連線的功能):

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include <regx51.h>

#define STX 0x02
#define ETX 0x03
unsigned char SendBuf[]="51015100peanut10";
unsigned char ReceiveBuf[16];
int receive_cnt=0;
unsigned char buf;
int count=1000;									//1秒=1000*1ms
int on_line_sec=0;							//連線秒數
int on_line_status=0;						//onlne or offline
int is_receive=0;								//是否有接收
int is_check=0; 								//檢查碼
unsigned char calculateLRC(unsigned char *d, int length);

// 使用函數的設定區
extern void LCD_Init(void);
extern void LCD_Out(unsigned char x, unsigned char y, unsigned char *text);
extern void LCD_Out_Cp(unsigned char *text);
extern void LCD_Chr(unsigned char x, unsigned char y, unsigned char c);
extern void LCD_Chr_Cp(unsigned char c);
extern void LCD_Cmd(unsigned char cmd);
extern void LCD_GotoXY(unsigned char x, unsigned char y);

// 使用命令的設定區
extern unsigned char LCD_CURSOR_ON;
extern unsigned char LCD_CURSOR_OFF;
extern unsigned char LCD_CLEAR;

void init_UART(unsigned int baudrate)
{
		SCON=0x52;
		TMOD=0x20;
#	TH1=256-((11059200/384)/baudrate);
	  TH1=0xE6;
		TL1=TH1;
		TR1=1;
}

void T0_int(void) interrupt 1
{
	TL0=(8192-1000)%32;						//重設設定值
	TH0=(8192-1000)/32;
	if(count==0)					//連線已經有1秒了嗎?
	{
		if(on_line_status)
			{
				on_line_sec++;
				on_line_sec%=100;
				LCD_Chr(2,16, on_line_sec%10+0x30);    //將接收到的資料送往顯示
				LCD_Chr(2,15, on_line_sec/10+0x30);    //將接收到的資料送往顯示
			}
		if(!is_receive)
			{
				LCD_Cmd(LCD_CLEAR);
				LCD_Out(2,1,"offline  ");
				on_line_status=0;
				on_line_sec=0;
			}
		else
			LCD_Out(2,1,"online   ");
		is_receive=0;	 
		count=1000;									//1秒count
	}
	else
		count--;										//count每1ms減1
}

void UART_int(void) interrupt 4		//串列中斷函式	
{
	if(RI==1)												//是不為接收中斷?
	{
		RI=0;													//完成後清除RI
		buf=SBUF;											//將接到的資料給buf
		if(is_check){
			is_check=0;
			if(buf != calculateLRC(ReceiveBuf, 16))
				LCD_Out(2,1,"check err");
			else
				LCD_Out(2,1,"online   ");
		}
		else if(buf == STX)
			receive_cnt=0;
		else if (buf == ETX)
		{
			LCD_Out(1,1,ReceiveBuf);
			is_check=1;
		}
		else
		{			
			ReceiveBuf[receive_cnt++]=buf;
			receive_cnt%=16;
		}
		is_receive=1;
		if(!on_line_status){
			on_line_sec=0;
			on_line_status=1;
			LCD_Out(2,1,"online   ");
			count=1000;	
		}
	}
	else
		TI=0;													//如果是傳送中斷,則清除TI,下次才方再傳送
}

void Delay_ms(unsigned int count) 						//延遲count*1ms函式
{
				unsigned int i,j;
				for(i=0;i<count;i++)
								for(j=0;j<123;j++);
}

unsigned char calculateLRC(unsigned char *d, int length)
{
	  unsigned char LRC = 0;  // LRC 的初始值
		int i;
    for (i = 0; i < length; i++) {
        LRC ^= d[i];  // 進行 XOR 運算
    }
    LRC ^= ETX;  // XOR 運算 ETX
    return LRC;
}

void main(void)
{
			unsigned int i;
			init_UART(1200);						//設定串列傳輸模式-9600bps
			ES=1;												//開啟串列中斷
			ET0=1;											//啟動計時器1
			EA=1;	                      //開啟總中斷
			TR0=1; 											//啟動計時器
	
			LCD_Init();									// LCD 初始化
			LCD_Cmd(LCD_CURSOR_ON);			// 將游標打開
			LCD_Chr(1,7,'8');						// LCD 在(1,7)位置顯示8
			LCD_Chr_Cp('0');						// LCD 在(1,8)位置顯示0
			LCD_Out_Cp("51");						// LCD 在(1,9)位置顯示51
			LCD_Cmd(LCD_CURSOR_OFF);		// 將游標關閉
			LCD_Out(1,1," ");	
			LCD_Out(2,1,"offline");			// LCD 在(2,1)位置顯示offline
			LCD_Out(2,15,"00");

			while(1)
			{
				SBUF=STX;
				Delay_ms(10);
				for(i=0;i<16;i++)
				{
					SBUF=SendBuf[i];					//傳送0-9
					Delay_ms(10);
				}
				SBUF=ETX;
				Delay_ms(10);
				SBUF=calculateLRC(SendBuf, 16);
				Delay_ms(1000);
			}
}

ESP32 CAM程式(感謝小霸王科技 施經理提供):

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/*
 *   按下IO0傳給8051
 * 
 */

// 定義引腳
const int buttonPin = 0;  // IO0 引腳
const int ledPin = 4;     // LED 引腳(通常是 GPIO 4)
#define RXD2 12
#define TXD2 13

// 定義字節常量
byte STX = 0x02;  // 開始標記
byte ETX = 0x03;  // 結束標記
byte ACK = 0x06;  // 確認標記

// 數據陣列
byte dataBytes[16] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
byte receivedData[18];  // 接收的數據
int receivedIndex = 0; // 接收數據的索引


// 定義變量

int dataIndex = 0;      // 接收數據的索引
bool receiving = false;  // 是否正在接收數據

unsigned long previousMillis = 0;  // 儲存上次更新的時間
const long interval = 1000;          // 設定間隔時間

// 計算 LRC 的函數
byte calculateLRC(byte *data, size_t length) {
    byte LRC = 0;  // LRC 的初始值
    for (size_t i = 0; i < length; i++) {
        LRC ^= data[i];  // 進行 XOR 運算
    }
    LRC ^= ETX;  // XOR 運算 ETX
    return LRC;
}

// 發送數據的函數
void sendData(byte *data, size_t length) {
    // 計算 LRC
    byte LRC = calculateLRC(data, length);

    // 構建完整數據包
    Serial2.write(STX);  // 發送 STX
    Serial2.write(data, length);  // 發送 DATA
    Serial2.write(ETX);  // 發送 ETX
    Serial2.write(LRC);  // 發送 LRC

    // 發送 ACK
//    Serial2.write(ACK);
}
// 處理接收的數據
void handleIncomingData() {
    while (Serial2.available()) {
        byte incomingByte = Serial2.read(); // 讀取字節
//        Serial.print("incomm:");
//        Serial.println(incomingByte,HEX);

        // 檢查是否是 STX
        if (incomingByte == STX) {
            receivedIndex = 0; // 重置索引,不存儲 STX
        } else if (receivedIndex < sizeof(receivedData)) {
            // 在 STX 和 ETX 之間接收數據
            receivedData[receivedIndex++] = incomingByte;
        }

        // 檢查是否接收到完整數據包
        if (receivedIndex >= 3 && receivedData[receivedIndex - 2] == ETX) {
            byte LRC = calculateLRC(receivedData, receivedIndex - 2); // 計算 LRC,不包括 ETX 和 LRC
            byte receivedLRC = receivedData[receivedIndex - 1]; // 最後一個字節是 LRC

            // 打印接收到的數據和 LRC
            Serial.print("Received Data: ");
            for (int i = 0; i < receivedIndex; i++) {
                Serial.print(receivedData[i], HEX); // 以十六進制格式顯示
                Serial.print(" ");
            }
            Serial.print("LRC: ");
            Serial.print(LRC, HEX);
            Serial.print("    receivedLRC: ");
            Serial.println(receivedLRC, HEX);

            // 檢查 LRC 是否匹配
            if (LRC == receivedLRC) {
              processReceivedData(receivedData, receivedIndex - 2);
            }
            else{
                Serial.println("LRC check failed!");
            }
            receivedIndex = 0; // 重置索引以接收下一個數據包
        }
    }
}

// 處理接收到的數據
void processReceivedData(byte *data, int length) {
    Serial.print("Received Data: ");
    for (int i = 0; i < length; i++) {
        dataBytes[i] = data[i];
        Serial.print(data[i], HEX); // 以十六進制格式顯示
        Serial.print(" ");
    }
    Serial.println();
}
void setup() {
    Serial.begin(115200);  // 初始化串口,波特率為 115200

    Serial2.begin(1200, SERIAL_8N1, RXD2, TXD2);
    pinMode(buttonPin, INPUT_PULLUP);  // 設定 IO0 為輸入,並啟用內部上拉電阻
    pinMode(ledPin, OUTPUT);             // 設定 LED 引腳為輸出
    digitalWrite(ledPin, LOW);           // 確保 LED 初始狀態為熄滅
}
void loop() {
    // 讀取按鈕狀態
    int buttonState = digitalRead(buttonPin);
    
    // 檢查按鈕是否被按下
    if (buttonState == LOW) { // 按鈕按下時,IO0 為 LOW
        dataBytes[0] = 0x48;  // 設置數據陣列的第一個字節
        //Serial.println("Button State: Pressed"); // 傳送狀態到 SERIAL
    } else {
        dataBytes[0] = 0x4C;  // 設置數據陣列的第一個字節
        //Serial.println("Button State: Not Pressed"); // 傳送狀態到 SERIAL
    }
    
 
    handleIncomingData();  // 處理接收到的數據
    // 檢查 dataBytes[1] 是否等於 0x48
    if (dataBytes[1] == 0x48) {
        digitalWrite(ledPin, HIGH);  // 點亮 LED
    } else {
        digitalWrite(ledPin, LOW);   // 熄滅 LED
    }

    yield(); // 讓 ESP32 檢查看門狗定時器
    //delay(500); // 延遲 500 毫秒
    // 非阻塞延遲
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
        previousMillis = currentMillis;
        // 在這裡執行需要延遲的代碼
        // 發送數據到 Serial2
        Serial.println("millis");
        sendData(dataBytes, sizeof(dataBytes) / sizeof(dataBytes[0]));
    } 
}


2024年10月12日 星期六

[8051] 實作檢查碼,若有錯則顯示錯誤

參考教材:單晶片微處理機實習,黃嘉輝,台科大出版

前一篇文章:設計簡單的通訊協定以POS機串接的通訊為例

程式碼:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include <regx51.h>

#define STX 0x02
#define ETX 0x03
unsigned char SendBuf[]="51015100peanut10";
unsigned char ReceiveBuf[16];
int receive_cnt=0;
unsigned char buf;
int count=1000;									//1秒=1000*1ms
int on_line_sec=0;							//連線秒數
int on_line_status=0;						//onlne or offline
int is_receive=0;								//是否有接收
int is_check=0; 								//檢查碼
unsigned char calculateLRC(unsigned char *d, int length);

// 使用函數的設定區
extern void LCD_Init(void);
extern void LCD_Out(unsigned char x, unsigned char y, unsigned char *text);
extern void LCD_Out_Cp(unsigned char *text);
extern void LCD_Chr(unsigned char x, unsigned char y, unsigned char c);
extern void LCD_Chr_Cp(unsigned char c);
extern void LCD_Cmd(unsigned char cmd);
extern void LCD_GotoXY(unsigned char x, unsigned char y);

// 使用命令的設定區
extern unsigned char LCD_CURSOR_ON;
extern unsigned char LCD_CURSOR_OFF;
extern unsigned char LCD_CLEAR;

void init_UART(unsigned int baudrate)
{
		SCON=0x52;
		TMOD=0x20;
		TH1=256-((11059200/384)/baudrate);
		TL1=TH1;
		TR1=1;
}

void T0_int(void) interrupt 1
{
	TL0=(8192-1000)%32;						//重設設定值
	TH0=(8192-1000)/32;
	if(count==0)					//連線已經有1秒了嗎?
	{
		if(on_line_status)
			{
				on_line_sec++;
				on_line_sec%=100;
				LCD_Chr(2,16, on_line_sec%10+0x30);    //將接收到的資料送往顯示
				LCD_Chr(2,15, on_line_sec/10+0x30);    //將接收到的資料送往顯示
			}
		if(!is_receive)
			{
				LCD_Cmd(LCD_CLEAR);
				LCD_Out(2,1,"offline");
				on_line_status=0;
				on_line_sec=0;
			}
		is_receive=0;	 
		count=1000;									//1秒count
	}
	else
		count--;										//count每1ms減1
}

void UART_int(void) interrupt 4		//串列中斷函式	
{
	if(RI==1)												//是不為接收中斷?
	{
		RI=0;													//完成後清除RI
		buf=SBUF;											//將接到的資料給buf
		if(is_check){
			is_check=0;
			if(buf != calculateLRC(ReceiveBuf, 16))
				LCD_Out(2,1,"check err");
		}
		else if(buf == STX)
			receive_cnt=0;
		else if (buf == ETX)
		{
			LCD_Out(1,1,ReceiveBuf);
			is_check=1;
		}
		else
		{			
			ReceiveBuf[receive_cnt++]=buf;
			receive_cnt%=16;
		}
		is_receive=1;
		if(!on_line_status){
			on_line_sec=0;
			on_line_status=1;
			LCD_Out(2,1,"online ");
			count=1000;	
		}
	}
	else
		TI=0;													//如果是傳送中斷,則清除TI,下次才方再傳送
}

void Delay_ms(unsigned int count) 						//延遲count*1ms函式
{
				unsigned int i,j;
				for(i=0;i<count;i++)
								for(j=0;j<123;j++);
}

unsigned char calculateLRC(unsigned char *d, int length)
{
	  unsigned char LRC = 0;  // LRC 的初始值
		int i;
    for (i = 0; i < length; i++) {
        LRC ^= d[i];  // 進行 XOR 運算
    }
    LRC ^= ETX;  // XOR 運算 ETX
    return LRC;
}

void main(void)
{
			unsigned int i;
			init_UART(9600);						//設定串列傳輸模式-9600bps
			ES=1;												//開啟串列中斷
			ET0=1;											//啟動計時器1
			EA=1;	                      //開啟總中斷
			TR0=1; 											//啟動計時器
	
			LCD_Init();									// LCD 初始化
			LCD_Cmd(LCD_CURSOR_ON);			// 將游標打開
			LCD_Chr(1,7,'8');						// LCD 在(1,7)位置顯示8
			LCD_Chr_Cp('0');						// LCD 在(1,8)位置顯示0
			LCD_Out_Cp("51");						// LCD 在(1,9)位置顯示51
			LCD_Cmd(LCD_CURSOR_OFF);		// 將游標關閉
			LCD_Out(1,1," ");	
			LCD_Out(2,1,"offline");			// LCD 在(2,1)位置顯示offline
			LCD_Out(2,15,"00");

			while(1)
			{
				SBUF=STX;
				Delay_ms(10);
				for(i=0;i<16;i++)
				{
					SBUF=SendBuf[i];					//傳送0-9
					Delay_ms(10);
				}
				SBUF=ETX;
				Delay_ms(10);
				SBUF=calculateLRC(SendBuf, 16);
				Delay_ms(1000);
			}
}

執行結果:

若把第149行改為SBUF=calculateLRC(SendBuf, 16)+1;
執行結果:


[8051]設計簡單的通訊協定以POS機串接的通訊為例

參考教材:單晶片微處理機實習,黃嘉輝,台科大出版

前一篇文章:偵測通訊狀態,顯示連線/斷線和秒數

POS機串接的通訊格式:通訊規格

程式碼:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <regx51.h>

#define STX 0x02
#define ETX 0x03
unsigned char SendBuf[]="51015100peanut10";
unsigned char ReceiveBuf[16];
int receive_cnt=0;
unsigned char buf;
int count=1000;									//1秒=1000*1ms
int on_line_sec=0;							//連線秒數
int on_line_status=0;						//onlne or offline
int is_receive=0;								//是否有接收

// 使用函數的設定區
extern void LCD_Init(void);
extern void LCD_Out(unsigned char x, unsigned char y, unsigned char *text);
extern void LCD_Out_Cp(unsigned char *text);
extern void LCD_Chr(unsigned char x, unsigned char y, unsigned char c);
extern void LCD_Chr_Cp(unsigned char c);
extern void LCD_Cmd(unsigned char cmd);
extern void LCD_GotoXY(unsigned char x, unsigned char y);

// 使用命令的設定區
extern unsigned char LCD_CURSOR_ON;
extern unsigned char LCD_CURSOR_OFF;
extern unsigned char LCD_CLEAR;

void init_UART(unsigned int baudrate)
{
		SCON=0x52;
		TMOD=0x20;
		TH1=256-((11059200/384)/baudrate);
		TL1=TH1;
		TR1=1;
}

void T0_int(void) interrupt 1
{
	TL0=(8192-1000)%32;						//重設設定值
	TH0=(8192-1000)/32;
	if(count==0)					//連線已經有1秒了嗎?
	{
		if(on_line_status)
			{
				on_line_sec++;
				on_line_sec%=100;
				LCD_Chr(2,16, on_line_sec%10+0x30);    //將接收到的資料送往顯示
				LCD_Chr(2,15, on_line_sec/10+0x30);    //將接收到的資料送往顯示
			}
		if(!is_receive)
			{
				LCD_Cmd(LCD_CLEAR);
				LCD_Out(2,1,"offline");
				on_line_status=0;
				on_line_sec=0;
			}
		is_receive=0;	 
		count=1000;									//1秒count
	}
	else
		count--;										//count每1ms減1
}

void UART_int(void) interrupt 4		//串列中斷函式	
{
	if(RI==1)												//是不為接收中斷?
	{
		RI=0;													//完成後清除RI
		buf=SBUF;											//將接到的資料給buf
		if(buf == 0x02)
			receive_cnt=0;
		else if (buf == 0x03)
			LCD_Out(1,1,ReceiveBuf);
		else 
			ReceiveBuf[receive_cnt++]=buf;
		is_receive=1;
		if(!on_line_status){
			on_line_sec=0;
			on_line_status=1;
			LCD_Out(2,1,"online ");
			count=1000;	
		}
	}
	else
		TI=0;													//如果是傳送中斷,則清除TI,下次才方再傳送
}

void Delay_ms(unsigned int count) 						//延遲count*1ms函式
{
				unsigned int i,j;
				for(i=0;i<count;i++)
								for(j=0;j<123;j++);
}

void main(void)
{
			unsigned int i;
			init_UART(9600);						//設定串列傳輸模式-9600bps
			ES=1;												//開啟串列中斷
			ET0=1;											//啟動計時器1
			EA=1;	                      //開啟總中斷
			TR0=1; 											//啟動計時器
	
			LCD_Init();									// LCD 初始化
			LCD_Cmd(LCD_CURSOR_ON);			// 將游標打開
			LCD_Chr(1,7,'8');						// LCD 在(1,7)位置顯示8
			LCD_Chr_Cp('0');						// LCD 在(1,8)位置顯示0
			LCD_Out_Cp("51");						// LCD 在(1,9)位置顯示51
			LCD_Cmd(LCD_CURSOR_OFF);		// 將游標關閉
			LCD_Out(1,1," ");	
			LCD_Out(2,1,"offline");			// LCD 在(2,1)位置顯示offline
			LCD_Out(2,15,"00");

			while(1)
			{
				SBUF=STX;
				Delay_ms(10);
				for(i=0;i<16;i++)
				{
					SBUF=SendBuf[i];					//傳送0-9
					Delay_ms(10);
				}
				SBUF=ETX;
				Delay_ms(10);
				Delay_ms(1000);
			}
}

執行結果: