相信大多數的人都有玩過遙控類的玩具,甚至在日常生活中也常常用到,例如家裡的電動門、汽車中控鎖......等,都使用到這種 RF (Radio Frequency) 通訊的技術。
本文中所要探討的是 RF 315MHz 長距離發射/接收模組 (TG-11A 與 TG-11B) 的控制方法,不使用額外的編碼與解碼晶片,而是使用 MCU (Micro-Controller Unit) 微控制器來負責發射與接收:發射端送出自訂字元,接收端接收自訂字元產生相對應的動作 (這裡是控制 LED 明滅)。
網路上關於照片中的模組所找到的資料都是基於八支腳位的,不過由於大部份接腳都是共用的,所以簡化之後的接腳只有 Vcc、GND和 DATA IN/OUT用的到。
文中所使用的模組都是 4-pin,有些接腳在使用時必須接在一起 (照片中可清楚看出)。
參考網站:
WinAVR AVR-GCC Tutorial - Running TX433 and RX433 RF modules with AVR microcontrollers
硬體線路:
發射線路:從左而右的四支接腳分別接 Vcc (pin-1, pin-2)、Data-In (pin-3)、GND (pin-4),其中比較重要的是 Data-In 接腳,這支接腳必須接到 MCU 的 TxD 接腳;另外 Vcc 接腳在本文中是接 +5V,我讓它跟 MCU 共用電源(你可以試試接 +3 ~ 12V)。
接收線路:從左而右的四支接腳分別接 Vcc (pin-1)、Data-Out (pin-2,pin-3)、GND (pin-4),其中比較重要的是 Data-Out 接腳,這支接腳必須接到 MCU 的 RxD 接腳;另外 Vcc 接腳在本文中是接 +5V,我讓它跟 MCU 共用電源,但是實際測試過可以用兩顆電池(+3V)來驅動,+3V 的電源剛好可以用在 ATtiny2313,這在下面測試時會講到。
電源是用 +9V 乾電池經穩壓晶片 7805 降壓到 +5V,輸出電流最大為 1A,剛好可以給本文中發射與接收的電路作測試用;一開始我是這樣想,以 ATtiny2313 做發射 AT89S51 做接收都正常運作,直到 AT89S51 做發射 ATtiny2313 做接收時,LED 閃爍的反應變的超慢,也不能說不正常,畢竟也正常運作,那時還沒想到這樣反過來做測試會吃這麼多電,因為電壓不足造成 MCU 一直 reset 重新啟動,而造成這種情形。
在使用上,發射與接收線路通常不會共用電源而是分開使用的,我是為了方便測試所以才接在一起,最後是在接收程式中加入 "hello word" 的開機 LED 閃爍,才得知這個問題,然後另外使用一個+3V的乾電池電源給 ATtiny2313 用,希望你不要發生像我一樣的情形。
下面是使用 ATtiny2313 與 AT89S51 時,發射與接收模組的接法。AT89S51 的震盪器(12 MHz)與 Reset 電路並沒有畫出你必須自行接上;ATtiny2313 直接接上電源即可,熔絲位請選擇 "Internal RC Osc. 8MHz; Start-up time: 14 CK + 65 ms",CLK/8 不使用。
"參考網站" 中使用 ATmega8 作為 RF 發射與接收的韌體開發晶片。為了無線傳輸時,發射與接收訊號能夠同步化,使用晶片中通用同步與非同步串列接收發射器 ( USART, Universal Synchronous and Asynchronous serial Receiver and Transmitter) 功能;為了避免無端干擾,設置了編碼與解碼封包的自定控制字元,原始程式的說明請上 "參考網站"。在本文中只針對修改及增加的部份多做說明。
基於 "參考網站" 中的資料,本文中所要實做的部分為:
ATtiny2313 (C語言) 發射 <<<<>>>> AT89S51 (C語言) 接收
ATtiny2313 (C語言) 發射 <<<<>>>> AT89S51(組合語言) 接收
AT89S51 (C語言) 接收 <<<<>>>> ATtiny2313 (C語言) 接收
AT89S51(組合語言) 接收 <<<<>>>> ATtiny2313 (C語言) 接收
因為比較熟 Keil C/assembly 和 AVR GCC,所以這六個程式除了AVR GCC 的程式之外,Keil C/Assembly 就依 "參考網站" 中的程式來重寫以達到同樣的功能,順便複習 Keil 組合語言。
ATtiny2313 RF發射程式需要修改的部份如下,主要是修改暫存器裡的設定
void USART_Init(void) { //Set baud rate UBRRL = (uint8_t)UBRRVAL; //low byte UBRRH = (UBRRVAL >> 8); //high byte //Enable Transmitter and Receiver and Interrupt on receive complete UCSRB = (1 << TXEN); //Set data frame format: asynchronous mode,no parity, 1 stop bit, 8 bit size UCSRC = (0 << UMSEL) | (0 << UPM1) | (0 << UPM0) | (0 << USBS) | (0 << UCSZ2) | (1 << UCSZ1) | (1 << UCSZ0);ATtiny2313 RF發射程式整理在此,按此下載。
ATtiny2313 RF接收程式修改的部份如下,除了暫存器修改之外,在 "Main_Init()" 裡加入了 LED 閃爍的效果,當 MCU 插上電源 LED 會明滅閃爍 5 次,以及修改中斷副程式 LED 所連接的位置,LED 是低態動作。
void USART_Init(void) { //Set baud rate UBRRL = (uint8_t)UBRRVAL; //low byte UBRRH = (UBRRVAL >> 8); //high byte //Set data frame format: asynchronous mode,no parity, 1 stop bit, 8 bit size UCSRC = (0 << UMSEL) | (0 << UPM1) | (0 << UPM0) | (0 << USBS) | (0 << UCSZ2) | (1 << UCSZ1) | (1 << UCSZ0); //Enable Transmitter and Receiver and Interrupt on receive complete UCSRB = (1 << RXEN) | (1 << RXCIE);//|(1<<TXEN); } ISR(USART_RX_vect) { //define variables uint8_t raddress, data, chk;//transmitter address //receive destination address raddress = USART_vReceiveByte(); //receive data data = USART_vReceiveByte(); //receive checksum chk = USART_vReceiveByte(); //compare received checksum with calculated if(chk == (raddress+data))//if match perform operations { //if transmitter address match if(raddress == RADDR) { if(data == LEDON) { PORTD &= ~(1<<PD6);//LED ON } else if(data == LEDOFF) { PORTD |= (1<<PD6);//LED OFF } else { //blink led as error PORTD |= (1 << PD6);//LED OFF _delay_ms(10); PORTD &= ~(1 << PD6);//LED ON } } } } void Main_Init(void) { uint8_t i = 0; DDRD = 0x40;//define port C pin 0 as output; // hello word for(;i < 5;i++) { PORTD &= ~(1 << PD6); // LED ON _delay_ms(150); PORTD |= (1 << PD6); //LED OFF _delay_ms(150); } //enable global interrupts sei(); }ATtiny2313 RF接收程式整理在此,按此下載。
AT89S51(Keil C) RF發射程式,結構上與原始程式一樣,主要增加 "delay_100ms()" 副程式做延遲的工作,因為 Keil 沒內建延遲程式可以呼叫,所以只好自己建一個;"ioinit()" 包含 UART 的設定與設定使用 Timer1 作為 baud rate 產生器,不需設定全局中斷(EA)。
#include <REGX51.H> typedef unsigned char tByte; //define receive parameters #define SYNC 0XAA// synchro signal #define RADDR 0x44 #define LEDON 0x11//switch led on command #define LEDOFF 0x22//switch led off command // delay 100ms void delay_100ms() { #pragma asm MOV R6, #250 delay_1: MOV R7, #200 DJNZ R7, $ DJNZ R6, delay_1 #pragma endasm } void ioinit(void) { // mode 1, 8-bit UART PCON |= 0x00; // SMOD = 0, double baud rate speed disable // SCON = SM0 SM1 SM2 REN TB8 RB8 TI RI = 01000000; // SM0 = 0, SM1 = 1 meas UART mode 1 SCON = 0x40; // baun rate, Timer1, mode 2 auto reload, 1200bps TMOD = 0x20; TL1 = 0xe6; TH1 = 0xe6; TR1 = 1; // start timer 1 } void send_byte(tByte const b) { SBUF = b; while(!TI); TI = 0; } void send_packs(tByte const radd, tByte const rcmd) { send_byte(SYNC); send_byte(radd); send_byte(rcmd); send_byte((radd+rcmd)); // check sum } void main(void) { ioinit(); for(;;) { send_packs(RADDR, LEDON); delay_100ms(); send_packs(RADDR, LEDOFF); delay_100ms(); } }
相對應的 Keil Assembly 的 RF 發射程式,請對照上一個程式。
;------------------------------------------------------------------------------ ; VARIABLES ;------------------------------------------------------------------------------ ; CONST DEFINES SYNC EQU 0xAA RADDR EQU 0x44 LEDON EQU 0x11 LEDOFF EQU 0x22 ; VARIABLE DEFINES CMD DATA 0x30 ;------------------------------------------------------------------------------ ; INTERRUPT VECTOR DEFINITIONS ;------------------------------------------------------------------------------ ORG 0000H ; STARTUP MEMORY ADDRESS JMP RESET ;------------------------------------------------------------------------------ ; MAIN PROGRAM ;------------------------------------------------------------------------------ RESET: MOV SP, #5FH IOINIT: ORL PCON, #00H ; SMOD = 0, DOUBLE BAUD RATE SPEED DISABLE MOV SCON, #01000000B ; UART MODE 1, 8-BIT MOV TMOD, #20H ; TIMER1, MODE 2(8-BIT AUTOLOAD), 1200bps MOV TL1, #0E6H MOV TH1, #0E6H SETB TR1 ; START TIMER 1 MAIN: ; send led on command MOV CMD, #LEDON LCALL SEND_PACKS ; delay 100 ms LCALL DELAY_100MS ; send led off command MOV CMD, #LEDOFF LCALL SEND_PACKS ; delay 100 ms LCALL DELAY_100MS JMP MAIN ;------------------------------------------------------------------------------ ; SUBROUTINE ;------------------------------------------------------------------------------ ; DELAY 100 ms ;------------------------------------------------ DELAY_100MS: MOV R6, #250 delay_1: MOV R7, #200 DJNZ R7, $ DJNZ R6, delay_1 RET ;------------------------------------------------ ; SEND PACKS FROM UART ; 1. synchronous signal ; 2. wireless device ID ; 3. command ; 4. check sum ;------------------------------------------------ SEND_PACKS: MOV SBUF, #SYNC ; synchronous signal JNB TI, $ CLR TI MOV SBUF, #RADDR ; wireless devive ID JNB TI, $ CLR TI MOV SBUF, CMD ; command JNB TI, $ CLR TI MOV A, CMD ADD A, #RADDR MOV SBUF, A ; check sum JNB TI, $ CLR TI RET ;------------------------------------------------------------------------------ END
AT89S51(Keil C) RF接收程式
#include <REGX51.H> #define INTERRUPT_UART 4 #define ON 0 #define OFF 1 // ASSIGN LED CONTROL BIT P0.0, ACTIVE LOW sbit LED = P0^0; // delay 10ms void delay_10ms() { #pragma asm MOV R6, #25 DEL: MOV R7, #200 DJNZ R7, $ DJNZ R6, DEL #pragma endasm } typedef unsigned char tByte; //define receive parameters #define SYNC 0XAA// synchro signal #define RADDR 0x44 #define LEDON 0x11//switch led on command #define LEDOFF 0x22//switch led off command void ioinit(void) // wait modify { // turn off LED LED = OFF; // mode 1, 8-bit UART PCON |= 0x00; // SMOD = 0, double baud rate speed disable // SCON = SM0 SM1 SM2 REN TB8 RB8 TI RI = 01010000; // SM0 = 0, SM1 = 1 meas UART mode 1 SCON = 0x50; // baun rate, Timer1, mode 2 auto reload, 1200bps TMOD = 0x20; TL1 = 0xe6; TH1 = 0xe6; TR1 = 1; // start timer 1 // interrupt ES = 1; // enable serial port interrupt EA = 1; // enable global interrupt } tByte USART_vReceiveByte(void) { // Wait until a byte has been received while(!RI); RI = 0; // Return received data return SBUF; } void UART_ISR() interrupt INTERRUPT_UART { // a-lu remark: 2011.02.21 // No implemented SYNC check before receive the byte of RADDR // Let's to wait and see the test result //define variables tByte raddress, cmd, chk;//transmitter address // find TX or RX caused interrupt if(TI) { // clear TI TI = 0; } else { //receive destination address raddress = USART_vReceiveByte(); //receive cmd cmd = USART_vReceiveByte(); //receive checksum chk = USART_vReceiveByte(); //compare received checksum with calculated if(chk == (raddress+cmd))//if match perform operations { //if transmitter address match if(raddress == RADDR) { if(cmd == LEDON) { LED = ON; //LED ON } else if(cmd == LEDOFF) { LED = OFF; //LED OFF } else { //blink led as error LED = OFF; //LED OFF delay_10ms(); LED = ON; //LED ON } } } } } int main(void) { ioinit(); for(;;) { PCON |= 0x01; // IDLE MODE } //nothing here interrupts are working return 0; }
相對應的 Keil Assembly 的 RF 發射程式,請對照上一個程式。
;------------------------------------------------------------------------------ ; VARIABLES ;------------------------------------------------------------------------------ ; CONST DEFINES SYNC EQU 0xAA RADDR EQU 0x44 LEDON EQU 0x11 LEDOFF EQU 0x22 ; VARIABLE DEFINES CMD DATA 0x30 ;------------------------------------------------------------------------------ ; INTERRUPT VECTOR DEFINITIONS ;------------------------------------------------------------------------------ ORG 0000H ; STARTUP MEMORY ADDRESS JMP RESET ;------------------------------------------------------------------------------ ; MAIN PROGRAM ;------------------------------------------------------------------------------ RESET: MOV SP, #5FH IOINIT: ORL PCON, #00H ; SMOD = 0, DOUBLE BAUD RATE SPEED DISABLE MOV SCON, #01000000B ; UART MODE 1, 8-BIT MOV TMOD, #20H ; TIMER1, MODE 2(8-BIT AUTOLOAD), 1200bps MOV TL1, #0E6H MOV TH1, #0E6H SETB TR1 ; START TIMER 1 MAIN: ; send led on command MOV CMD, #LEDON LCALL SEND_PACKS ; delay 100 ms LCALL DELAY_100MS ; send led off command MOV CMD, #LEDOFF LCALL SEND_PACKS ; delay 100 ms LCALL DELAY_100MS JMP MAIN ;------------------------------------------------------------------------------ ; SUBROUTINE ;------------------------------------------------------------------------------ ; DELAY R5 x 100 ms ; before call it should set R5 value ;------------------------------------------------ DELAY_100MS: ;delay: MOV R6, #250 MOV R6, #250 delay_1: MOV R7, #200 DJNZ R7, $ DJNZ R6, delay_1 ; DJNZ R5, delay RET ;------------------------------------------------ ; SEND PACKS FROM UART ; 1. synchronous signal ; 2. wireless device ID ; 3. command ; 4. check sum ;------------------------------------------------ SEND_PACKS: MOV SBUF, #SYNC ; synchronous signal JNB TI, $ CLR TI MOV SBUF, #RADDR ; wireless devive ID JNB TI, $ CLR TI MOV SBUF, CMD ; command JNB TI, $ CLR TI MOV A, CMD ADD A, #RADDR MOV SBUF, A ; check sum JNB TI, $ CLR TI RET ;------------------------------------------------------------------------------ END
AT89S51 與 ATtiny2313 接收程式中,AT89S51 的中斷副程式同時處理 UART 傳送 (TxD) 與接收 (RxD) 觸發的中斷,而 ATtiny2313 (應該 AVR都是一樣的) 是分開處理的。因此在處理 AT89S51 的 UART 中斷時也要同時注意中斷是由哪一個所引起,雖然在接收程式可以不去管 TxD 所造成的中斷,但為了避免錯誤,所以只要是由 TxD 所引起的 UART 中斷,都直接將 TI設置為 0並直接返回,這是在撰寫 AT89S51 時要注意到的。
AT89S51 發射與接收的 Keil 專案檔整理在此,按此下載。
編譯後產生 .HEX 然後燒錄進你的晶片,開始接下來的測試。
上機測試:
上面所提供的六個韌體程式都以實際測試過。
下面影片中,RF發射端使用 AT89S51,電源供給 +5V;RF 接收端使用 ATtiny2313 ,電源供給 +3V。
不管你發射與接收是使用哪一個晶片,正常的動作情形就像影片一樣!
請問一下
回覆刪除接收和發射能不能只靠 89s51 ?
還是一定要靠 ATtiny2313
都可以!
回覆刪除89s51與Attiny2313都有附發送與接收的程式在上面,是可以互相混用以及使用同一種晶片做發送與接收的功能
問一下
回覆刪除發射器跟接收器,如要接天線的話,是要接在哪裡??
想請問神手大大一個問題!!!
回覆刪除我的訊號頻率約50Hz ,結果tg-11 來不及變換.....
遙控的訊號頻率不能太高嗎? 50Hz不行?
版主,想請問一下,RF無線傳輸是否為"同步"串列傳輸呢,8051那隻程式傳送端和發送端皆設有同步訊號,但你接收端的接收函式名稱是寫USART_vReceiveByte(),這表示同時擁有同步跟非同步功能?
回覆刪除串列阜中斷函式那裏你是寫_UART_ISR(),UART為非同步串列傳輸八,既然為非同步,為何還需要那同步訊號呢? 有點不是很明白,想請您指點,謝謝~
您好,我想詢問一下,我在接收的地方想收到數據後,再回送訊號,那接收端程式該怎麼寫好呢? 是不是可以給我些建議呢,謝謝您。
回覆刪除我對此產品非常有興趣,是否可談誤
回覆刪除請問兩端天線要如何選擇?傳送距離大約有多遠?
回覆刪除謝謝!
在這篇網頁 (http://ruten-proteus.blogspot.tw/2013/03/Wireless-RF-HT12DE.html) 搜尋"天線長度計算"這一節,有關於天線計算的說明。
刪除至於傳輸長度,要看有無遮蔽物、發送與接收功率。以這一組來說,大概空曠處 50-70米以上。
請問有可能做到多個不同發送端同時發送不同的訊號給一個接收端,而接收端仍能辦別出資料及發送端嗎?
回覆刪除可以!
刪除提供你一個網站,看一下這個 Arduino VirtualWire函式庫。
下面是一個使用的範例
http://ruten-proteus.blogspot.tw/2014/11/rgb-led-arduino-machester.html?showComment=1455800559297
簡單的作法:就是設定每一個送出的訊息中包含每一個裝置的 ID,讓接收端以此做為辨識。
我研究研究。感謝!
刪除請問一下,AT89S51(Keil C) RF發射程式,其中做delay的部分
回覆刪除{
#pragma asm
MOV R6, #250
delay_1: MOV R7, #200
DJNZ R7, $
DJNZ R6, delay_1
#pragma endasm
}
我用Keil uVision5開發環境去跑,會出現Error耶,是因為組合語言的關係嗎?
可能是你的專案檔沒有設定好輸出組合語言的選項,可以參考這篇網頁文章的說明,對照一下你現在的設定
刪除http://wenku.baidu.com/view/30159a21192e45361066f533.html
若還是有問題,要去找一下 Keil5 相關的資料再看看!
請問一下 如果要控制馬達 程式要怎麼修改
回覆刪除根據自定義的字元,傳送控制字元在接收端的 UART_ISR() 裡面做修改
刪除請問可以再上傳一次ATtiny2313 RF發射與接收的程式嗎? 原文的連結點資源被刪除了
回覆刪除