Phan tich thuat toan: thuc hien lenh dieu khien tu PC qua RS232

Chào các bạn.

Không biết ai đã đọc bài viết của mình PIC16F887 – Điều khiển thời gian đóng cắt một led từ PC qua UART chưa. Trong này, mình có thực hiện đặt thời gian đóng cắt từ PC bằng lệnh với cú pháp.

Txyzt#: trong đó  xyzt là thời gian tính theo hệ hexa.

Đây là đoạn chương trình xử lý ngắt UART:

void RxIntFcn(void){
UART_Data = UART_Read();
UART_PrChar(UART_Data);
// Detect set time command
// as format: Txy#
switch (progress){
case 0:                //Initialize
if(UART_Data == 'T')
progress = 1;
else
progress = 0;
switch(UART_Data){
case '1':
//RB6       = 1;
led1_cntL = 0x6F; // 1/9 s = 111 ms
led1_cntH = 1;
break;
case '2':
//RB6       = 1;
led1_cntL = 0xDE; // 2/9
led1_cntH = 0;
break;
case '3':
//RB5      = 1;
led1_cntL = 0x4D;    // 1s = 1000 = 0x03E8
led1_cntH = 0x1;
break;
case '4':
//RB5      = 1;
led1_cntL = 0xBC;    // 5s = 5000 = 0x1388
led1_cntH = 0x01;
break;
case '5':
//RB5      = 1;
led1_cntL = 0x2B;    // 5s = 5000 = 0x1388
led1_cntH = 0x02;
break;
case '6':
//RB5      = 1;
led1_cntL = 0x9A;    // 5s = 5000 = 0x1388
led1_cntH = 0x02;
break;
case '7':
//RB5      = 1;
led1_cntL = 0x09;    // 5s = 5000 = 0x1388
led1_cntH = 0x03;
&
#160;                   break;
case '8':
//RB5      = 1;
led1_cntL = 0x78;    // 5s = 5000 = 0x1388
led1_cntH = 0x03;
break;
case '9':
//RB5      = 1;
led1_cntL = 0xE7;    // 5s = 5000 = 0x1388
led1_cntH = 0x03;
break;
case '0':
//RB5      = 1;
led1_cntL = 0xE8;    // 5s = 5000 = 0x1388
led1_cntH = 0x03;
break;
default:
PORTB   &= 0x80;
};
break;
case 1:                // Received 'T' character
// Determind next state
if (ishexa(UART_Data) == 1){
progress = 2;
// Write data to acc1
acc1     = ascii2num(UART_Data);
}
else{
UART_PrString(" Command error");
progress = 0;
};
break;
case 2:                // Received 'x' character
if (ishexa(UART_Data) == 1){
progress = 3;
// Write data to acc2
acc2     = ascii2num(UART_Data);
}
else{
UART_PrString(" Command error");
progress = 0;
};
break;
case 3:                // Received 'x' character
if (ishexa(UART_Data) == 1){
progress = 4;
// Write data to acc2
acc3     = ascii2num(UART_Data);
}
else{
UART_PrString(" Command error");
progress = 0;
};
break;
case 4:                // Received 'x' character
if (ishexa(UART_Data) == 1){
progress = 5;

;            // Write data to acc2
acc4     = ascii2num(UART_Data);
}
else{
UART_PrString(" Command error");
progress = 0;
};
break;
case 5:
if (UART_Data == '#'){
progress = 0;
// Write 'OK' statement
UART_PrString(" Timer is set");
// Update data from ACC to led1_counter_acc
led1_cnt_acc1 = (acc1<<4) | acc2;
led1_cnt_acc2 = (acc3<<4) | acc4;
}
else{
UART_PrString(" Command error");
progress = 0;
};
break;
default: progress = 0;
break;
};

// On, off command
switch(UART_Data){
case 'P':        // On led
// Update led1_counter
led1_cntH = led1_cnt_acc1;
led1_cntL = led1_cnt_acc2;
break;
case 'S':
// Clear led1_counter content
led1_cntH = 0;
led1_cntL = 0;
break;
};
}

Thuật toán mình sử dụng rất đơn giản: dùng một biến progress là biến quá trình. Mặc định giá trị này là 0, khi nhận dc đúng kí tự T thì biến sẽ có giá trị = 1. Khi đó, nó sẽ kiểm tra tiếp theo có phải gõ vào là chữ số từ 0 đến 9, và từ A đến F hay không.Mỗi trạng thái, khi nhận đúng đều chuyển từ giá trị string sang giá trị số, ví dụ: kí tự ‘0’ chuyển thành giá trị unsigned char là 1. Xem hàm này trong hàm system.h. Nếu đúng thì progress tiếp tục tăng đến trạng thái kiểm tra tiếp theo, nếu không nó sẽ báo lỗi “Command Error” gửi lên PC.

Tiếp tục, đến cuối cùng khi nhận xong kí tự # thì tức là đã nhận đúng lệnh và thực hiện gán dữ liệu để lấy ra byte cao và byte thấp của giá trị nhập vào.

Đây là hàm system.h

bit ishexa(unsigned char a){
if ((a >= ‘0′ && a<= ‘9′) || (a>= ‘A’ && a<= ‘F’))
return 1;
else return 0;
};

// Convert from ASCII to number
unsigned char ascii2num(unsigned char a){
if( a >= ‘0′ && a<= ‘9′)
return (a-’0′);
else
return (a-’A’ + 0×0A);
}

Hi vọng phân tích của mình làm các bạn hiểu được cách để thực hiện các lệnh điều khiển từ PC hiệu quả.

Chúc các bạn thành công.

{ 2 comments… add one }
  • VU August 4, 2008, 8:42 pm

    Giúp mình quét led ma trận 8×8 với!Mình không biết làm sao để đưa ra một kí tự cả. Minh dùng quét theo cột. Dùng con atmega 16. Giúp mình với!

    Reply
  • soivaho July 27, 2012, 3:33 pm

    Chào bạn Bắc. Mình là Tiến, ở SG.
    Mình là người mới làm quen với PIC. Mình thấy nhiều bài viết của bạn và rất ngưỡng mộ bạn.
    Mình đang tập viết PIC16f887 điều khiển con graphic 128×64 TG12864-01: hiện vệt dọc tại: CS1, PAGE 0, COLUM 1.
    Chẳng hiểu sao mình làm mãi không được theo datasheet. Bạn có thể giúp mình về trình tự để hiển thị nó không? Bạn email cho mình nhé: soivaho@gmail.com

    Reply

Leave a Comment