紅外線遙控車
Re: 紅外線遙控車
代碼: 選擇全部
/* 紅外線遙控車
David Johnson-Davies - www.technoblogy.com - 2015年7月20日
ATtiny85 @ 1 MHz (內部振盪器; BOD 禁用)
CC BY 4.0
授權條款: 創作共用 署名 4.0 國際 授權協議:
http://creativecommons.org/licenses/by/4.0/
*/
volatile int NextBit; // 下一位元
volatile unsigned long RecdData; // 接收到的資料
// 馬達控制 **********************************************
void ReceivedCode (boolean Repeat) {
static int Left, Right, Speed = 127;
// 檢查是否來自正確的遙控器
if ((RecdData & 0xFFFF) != 0xbF00) return;
if (Repeat) return; // 忽略按鍵持續按下
// 讀取按下的按鍵
int key = RecdData >> 16 & 0xFF;
// 馬達命令
if ((key >= 0x10) && (key <= 0x1A)) Speed = ((key - 16) * 12) + 7;
else if (key == 0x05) { Left = 2; Right = 2; } // 前進
else if (key == 0x0D) { Left = -2; Right = -2; } // 後退
else if (key == 0x08) { Left = 2; Right = 1; } // 左轉
else if (key == 0x0A) { Left = 1; Right = 2; } // 右轉
else if ((key == 0x06) || (key == 0x09)) { Left = 0; Right = 0; } // 停止
else if (key == 0x0E) { Left = 2; Right = -2; } // 旋轉
//
if (Left >= 0) {
digitalWrite(0, LOW);
OCR1A = Left * Speed;
} else {
digitalWrite(0, HIGH);
OCR1A = 255 + (Left * Speed);
}
if (Right >= 0) {
digitalWrite(3, LOW);
OCR1B = Right * Speed;
} else {
digitalWrite(3, HIGH);
OCR1B = 255 + (Right * Speed);
}
}
// 紅外線控制 **********************************************
// 中斷服務例程 - 每次PB2下降沿時調用
ISR (INT0_vect) {
int Time = TCNT0;
int Overflow = TIFR & 1<<TOV0;
// 持續尋找 AGC 脈衝和間隙
if (NextBit == 32) {
if ((Time >= 194) && (Time <= 228) && (Overflow == 0)) {
RecdData = 0; NextBit = 0;
} else if ((Time >= 159) && (Time <= 193) && (Overflow == 0)) ReceivedCode(1);
// 資料位元
} else {
if ((Time > 44) || (Overflow != 0)) NextBit = 32; // 無效 - 重新啟動
else {
if (Time > 26) RecdData = RecdData | ((unsigned long) 1<<NextBit);
if (NextBit == 31) ReceivedCode(0);
NextBit++;
}
}
TCNT0 = 0; // 清除計數器
TIFR = TIFR | 1<<TOV0; // 清除溢出
GIFR = GIFR | 1<<INTF0; // 清除 INT0 標誌
}
// 設置 **********************************************
void setup() {
pinMode(0, OUTPUT);
pinMode(1, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
// 設置 Timer/Counter0 用於紅外線接收器 (假設時鐘頻率為 1MHz)
TCCR0A = 0; // 無比較匹配
TCCR0B = 3<<CS00; // 預分頻 /64
// 設置 INT0 中斷在 PB2 上
MCUCR = MCUCR | 2<<ISC00; // 下降沿中斷
GIMSK = GIMSK | 1<<INT0; // 啟用 INT0
NextBit = 32; // 等待 AGC 開始脈衝
// 設置 Timer/Counter1 用於 PB1 和 PB4 上的快 PWM
TCCR1 = 1<<CTC1 | 1<<PWM1A | 2<<COM1A0 | 7<<CS10;
GTCCR = 1<<PWM1B | 2<<COM1B0;
}
void loop() {
// 所有操作都在中斷中完成!
}