Hi,
Lâu rồi không tham gia diễn đàn, nay trở lại góp vui với bà con MSP430 chương trình nháp điều khiển từ xa dùng Remote của TV, DVD, vv... của Sony, Samsung, GL, Panasonic, vv... trừ mấy loại của Trung Quốc. Đây là chương trình nháp, muốn ứng dụng thì phải code bổ sung vào, mục đích là để cho các bác vọc MSP430 với KIT MSP430 LaunchPad. Trong ví dụ này, các bác học cách sử dụng ADC (single conversion), sử dụng Timer, các ngắt và chế độ tiết kiệm năng lượng.
Mô tả sơ hoạt động của chương trình như sau (nhìn ảnh dưới nhé):
Để điều khiển được trước tiên phải dạy cho mạch các lệnh điều khiển. Vì bộ nhớ có hạn nên mạch chỉ thực hiện được 6 lệnh điều khiển. Việc dạy lệnh điều khiển cho mạch được thực hiện bằng cách vặn biến trở về bên trái đến khi màn hình hiển thị chữ SET. Tiếp theo vặn biến trở bên phải để chọn lệnh (từ 0 đến 5). Và bấm nút trên remote 4 lần để mạch ghi nhớ lệnh. Khi lệnh được ghi nhớ thì đèn báo sẽ sáng lên giúp người dùng nhận biết và chuyển qua dạy cho lệnh mới. Vặn biến trở bên phải qua mã lệnh mới và thực hiện dạy lệnh mới cho mạch. Sau khi dạy xong lệnh cho mạch thì vặn biến trở bên phải qua chế độ hoạt động, màn hình sẽ hiển thị chữ RUN. Lúc này bạn bấm lệnh nào thì màn hình sẽ hiển thị lệnh đó và thực hiện lệnh đó (trong phạm vi ví dụ chỉ thực hiện việc Bật đèn). Nếu bấm sai lệnh thì sẽ thực hiện Tắt đèn.
Có thể mở rộng thêm các tính năng khác như hẹn giờ, đồng hồ vv...
Một vài ảnh:
KIT MSP430 LaunchPad
Mạch test
Chế độ dạy lệnh
Chế độ hoạt động
Các biến trở dùng để dạy và điều khiển
Và cuối cùng là code
Lâu rồi không tham gia diễn đàn, nay trở lại góp vui với bà con MSP430 chương trình nháp điều khiển từ xa dùng Remote của TV, DVD, vv... của Sony, Samsung, GL, Panasonic, vv... trừ mấy loại của Trung Quốc. Đây là chương trình nháp, muốn ứng dụng thì phải code bổ sung vào, mục đích là để cho các bác vọc MSP430 với KIT MSP430 LaunchPad. Trong ví dụ này, các bác học cách sử dụng ADC (single conversion), sử dụng Timer, các ngắt và chế độ tiết kiệm năng lượng.
Mô tả sơ hoạt động của chương trình như sau (nhìn ảnh dưới nhé):
Để điều khiển được trước tiên phải dạy cho mạch các lệnh điều khiển. Vì bộ nhớ có hạn nên mạch chỉ thực hiện được 6 lệnh điều khiển. Việc dạy lệnh điều khiển cho mạch được thực hiện bằng cách vặn biến trở về bên trái đến khi màn hình hiển thị chữ SET. Tiếp theo vặn biến trở bên phải để chọn lệnh (từ 0 đến 5). Và bấm nút trên remote 4 lần để mạch ghi nhớ lệnh. Khi lệnh được ghi nhớ thì đèn báo sẽ sáng lên giúp người dùng nhận biết và chuyển qua dạy cho lệnh mới. Vặn biến trở bên phải qua mã lệnh mới và thực hiện dạy lệnh mới cho mạch. Sau khi dạy xong lệnh cho mạch thì vặn biến trở bên phải qua chế độ hoạt động, màn hình sẽ hiển thị chữ RUN. Lúc này bạn bấm lệnh nào thì màn hình sẽ hiển thị lệnh đó và thực hiện lệnh đó (trong phạm vi ví dụ chỉ thực hiện việc Bật đèn). Nếu bấm sai lệnh thì sẽ thực hiện Tắt đèn.
Có thể mở rộng thêm các tính năng khác như hẹn giờ, đồng hồ vv...
Một vài ảnh:
KIT MSP430 LaunchPad
Mạch test
Chế độ dạy lệnh
Chế độ hoạt động
Các biến trở dùng để dạy và điều khiển
Và cuối cùng là code
Code:
#include <msp430g2231.h> #define _S 11 #define _E 12 #define _T 13 #define _R 14 #define _U 15 #define _N 16 #define SETTING 0 #define RUNNING 1 const unsigned char LedCode[17] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0xFF, 0x92, 0x86, 0x87, 0xCE, 0xE3, 0xAB}; //codes of led7 from 0 to 9 const unsigned char LedID[4] = {0x01, 0x02, 0x04, 0x08}; // active led7 const unsigned int AdcChanel[2] = {INCH_1, INCH_2}; volatile unsigned char Number, Dot, Blink; volatile unsigned char LedBuffer[4] = {0, 0, 0, 1}; // test data volatile unsigned char Scene; volatile unsigned char Buffer[24]; volatile unsigned long Command[6]; volatile unsigned long IrCode; volatile unsigned char BitCounter, StartBit; void update(void); /* * main.c */ int main(void) { WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer P1SEL = BIT1 + BIT2; P1DIR = 0xF1; P1REN = 0x00; ADC10CTL0 = ADC10SHT_0 + SREF_0 + ADC10ON; // + ADC10IE; // ADC10ON, interrupt enabled ADC10CTL1 = ADC10SSEL_0 + AdcChanel[0]; // input A1 ADC10AE0 |= BIT1 + BIT2; ADC10CTL0 |= ENC + ADC10SC; TACTL |= TASSEL_1 + MC_1;// + TAIE; // Timer A source from ACLK, up mode, Timer A interrupt enable CCR0 = 655; // period approximately 20ms CCR1 = 131; CCTL1 = CCIE; P1IE = BIT3; // enable interrupt P1.3 P1IES = BIT3; // H2L trigger interrupt StartBit = 1; // indicate start of frame P1OUT &= ~BIT0; _bis_SR_register(LPM3_bits + GIE); } // interrup port 1.3 #pragma vector = PORT1_VECTOR void __interrupt port1_isr(void) { if(StartBit) { TAR = 0; // reset Timer A counter CCTL0 = CCIE; // enable CC0 interrupt BitCounter = 0; // reset BitCounter StartBit = 0; // clear start of frame status } else if(BitCounter < 23) { Buffer[BitCounter] = TAR; // get Timer A counter TAR = 0; // reset Timer A counter BitCounter++; } P1IFG &= ~BIT3; // clear interrupt flag } // interrupt capture/compare 0 #pragma vector = TIMERA0_VECTOR void __interrupt cc0_isr(void) { unsigned char min, max, average, i; static unsigned char count; static unsigned long temp; CCTL0 &= ~CCIE; // disable CC0 interrupt StartBit = 1; // set start of frame if(BitCounter < 5) return; // ignore if interference // decode min = 0xFF; max = 0x00; for(i = 1; i < BitCounter; i++) { if(Buffer[i] < min) min = Buffer[i]; if(Buffer[i] > max) max = Buffer[i]; } average = (max + min) / 2; IrCode = 0; for(i = 1; i < BitCounter; i++) { IrCode <<= 1; if(Buffer[i] > average) IrCode++; } if(Scene == SETTING) { if(IrCode != temp) { temp = IrCode; count = 0; P1OUT &= ~BIT0; } else if(++count >= 3) { Command[LedBuffer[0]] = IrCode; count = 0; P1OUT |= BIT0; } } else if(Scene == RUNNING) { for(i = 0; i < 6; i++) { if(IrCode == Command[i]) { LedBuffer[0] = i; P1OUT |= BIT0; break; } else P1OUT &= ~BIT0; } } } #pragma vector = TIMERA1_VECTOR void __interrupt taif_isr(void) { static volatile unsigned char i = 0, count, blink_counter, last_id = BIT0; unsigned char k; unsigned char temp; if(TAIV & TAIV_TACCR1) { CCR1 += 100; if(CCR1 > 655) CCR1 = 100; // scan led7 if(i >= 3) // set led7 id i = 0; else i++; if(++blink_counter >= 50) { blink_counter = 0; if(Blink < 4) last_id ^= BIT0; else last_id = 0; } temp = LedID[i] << 4; for(k = 0; k < 4; k++) { //if(last_id && ((k + Blink) == 3)) P1OUT |= BIT5; if(last_id && ((Blink + k) == 3)) P1OUT |= BIT5; else { if(temp & BIT7) P1OUT &= ~BIT5; // Apply Led ID data else P1OUT |= BIT5; } P1OUT |= BIT6; // Clock Shift pulse temp <<= 1; P1OUT &= ~BIT6; } temp = LedCode[LedBuffer[i]]; //if(i == 2) temp &= ~BIT7; // display dot sign at led 2 for(k = 0; k < 8; k++) { if(temp & BIT7) P1OUT |= BIT5; else P1OUT &= ~BIT5; P1OUT |= BIT6; temp <<= 1; P1OUT &= ~BIT6; } P1OUT |= BIT7; _NOP(); P1OUT &= ~BIT7; if(++count >= 40) { count = 0; update(); } } } void update(void) { unsigned long adc_value; unsigned char now; static unsigned char channel, last = 0xFF;//, last_blink; if(ADC10CTL0 & ADC10BUSY) { return; } adc_value = ADC10MEM; ADC10CTL0 &= ~ENC; // Disable conversion if(channel == 0) { Scene = (unsigned char)(adc_value * 2 / 1023); if(Scene == SETTING) { LedBuffer[3] = _S; LedBuffer[2] = _E; LedBuffer[1] = _T; Blink = 0; } else if(Scene == RUNNING) { LedBuffer[3] = _R; LedBuffer[2] = _U; LedBuffer[1] = _N; Blink = 0xFF; } channel = 1; } else { //LedBuffer[0] = (unsigned char)(adc_value * 6 / 1023); now = (unsigned char)(adc_value * 6 / 1023); if(last ^ 0xFF) // Ignore the first value { if(now < last) { if((LedBuffer[0] + now) <= last) LedBuffer[0] = 0; else LedBuffer[0] = LedBuffer[0] + now - last; } else if(now > last) { LedBuffer[0] = LedBuffer[0] + now - last; if(LedBuffer[0] > 5) LedBuffer[0] = 5; } } last = now; channel = 0; if(Scene == RUNNING) { // do command of LedBuffer[0] value } } ADC10CTL1 = AdcChanel[channel]; ADC10CTL0 |= ENC + ADC10SC; // Enable, start conversion }
Comment