Microcontroller C Code Sample


Arduino + ENC28J60 การเชื่อมต่อ Arduino กับไอซี ethernet ENC28J60

โพสต์1 พ.ค. 2555 07:47โดยวิสิทธิ์ แผ้วกระโทก   [ อัปเดต 24 ม.ค. 2557 21:07 ]

Microcontroller C Code Sample



Arduino + ENC28J60 การเชื่อมต่อ Arduino กับไอซี ethernet ENC28J60



    ในการที่เราจะทำให้ไมโครคอนโทรลเลอร์ เชื่อมต่อ สื่อสารกันผ่านทาง Network ไม่ใช่เรื่องง่ายเลย เอกสารค่อนข้างเยอะที่จะต้องทำความเข้าใจ ซึ่งนับว่าเป็นปัญหาสำหรับ มือใหม่ และคนที่ต้องการทำโปรเจคเรื่องนี้ให้สำเร็จในเวลาอันรวดเร็ว (ไม่นับคนที่คุ้นเคยกับเรื่องพวกนี้แล้วนะครับ) แต่ สำหรับ Arduino แล้ว ไม่ว่าเรื่องอะไร ก็ดูจะัง่ายไปหมด แม้กระทั่งเรื่องการเชื่อมต่อกับ network แล้ว ก็กลายเป็นเรื่องง่ายทันที เพื่อนสามารถทดลอง และทำตามจนประสบผลสำเร็จได้อย่าง ไม่ยากเย็น เลย 

    ในตัวอย่างที่ผมนำมาเสนอ ตอนนี้ เป็นการนำไมโครคอนโทรลเลอร์ ตัวเก่ง Arduino Freeduno ที่ผมมีอยู่ เชื่อมต่อกับ Ethernet ภายในบ้านผม ผ่านพอร์ตเนตเวิร์คจาก router กับโมดูลเนตเวิร์คสำเร็จรูป ET-MINI ENC28J60 ของบริษัท ETT ซึ่งจะต้องเชื่อมต่อกันทาง SPI แต่ทั้งนี้ ทั้งนั้น เมื่อเราทดลองผ่านไลบรารี่ของ arduino แล้ว เรื่องยากๆ พวกนั้น เราก็แทบที่จะไม่ต้องไปคิดเลย ว่าจะต้องทำอย่างไร เรามาเริ่มกันเลยดีกว่าครับ 

อันดับแรก ก็ โหลดไลบรารี่มาทดลองกันได้ ที่นี่  จากนั้น ก็เชื่อมต่อบอร์ด Arduino กับ ET-MINI ENC28J60 ตามรูปที่แสดงด้านล่างเลยครับ 


ในที่นี้ ผมทดลองให้ ทำการอ่านค่าจาก Temperature sensor แล้วแสดงผลผ่านหน้าโค๊ดเว็บเพจที่ฝังอยู่ภายในโค๊ด Arduino ด้วยครับ ก็ทำตามตัวอย่างในวีดีโอกันได้เลย 




ดูแล้ว ไม่น่าจะยากเลยใช่ไหมครับ หากต้องการความท้าทายมากกว่า นี้ ก็ลองเขียนโค๊ดติดต่อดูเอาเองนะครับ ^^ 

Arduino ไฟวิ่งฝนดาวตก

โพสต์4 พ.ค. 2554 20:38โดยวิสิทธิ์ แผ้วกระโทก   [ อัปเดต 18 ม.ค. 2557 07:16 ]

Microcontroller C Code Sample

Arduino ไฟวิ่งฝนดาวตก

หลังจากได้ซื้อบอร์ด Freeduino V1.16 จากป๋าช้างมา ผมว่า Arduino มันเล่นง่ายจริงๆ นะ สไตล์การเขียนโค๊ดเหมือนพวก processing ผมไม่แน่ใจว่าเค้าเรียกการเขียนโค๊ดแบบนี้ เค้าเรียกว่าอะไร รู้แค่ว่า Arduino มันมีฟังก์ชั่นหลักอยู่ 2 ฟังก์ชั่น คือ void setup() และ void loop() แค่สองฟังก์ชั่นที่เค้าบังคับ เท่านั้่น ก็สามารถสั่งให้ Arduino ทำงานได้แหละ

แบบนี้ ก็ลองกันสักหน่อย แน่นอนครับ โค๊ดแรกเลย ต้องทำไฟกระพริบให้ได้ก่อน เพราะจะได้เป็นการเช็คว่า เราสามารถโปรแกรมลงบนบอร์ดได้จริง แต่วันนี้ พิเศษสักหน่อย เราจะมาทำไฟวิ่งฝนดาวตกกันครับ

Arduino มีโค๊ดที่เป็นตัวอย่างค่อนข้างเยอะ แล้วก็ค่อนข้างจะครบถ้วนให้เราศึกษางานทางด้าน Embedded System เราก็จะนำตัวอย่างโค๊ดของ Arduino ที่ชื่อว่า Fading มาทำการประยุกต์ในการทำไฟวิ่งฝนดาวตก กัน

หลักการคร่าวๆ ก็คือ ในการทำให้หลอด LED สว่างมาก-น้อย เราจะทำการเปลี่ยนแปลงแรงดันขาออก ให้อยู่ในรูบ Analog output ซึ่งที่ขาของ digital output แล้วไม่สามารถทำได้ตรงๆ แต่เราสามารถเปลี่ยนแปลงแรงดันค่าเฉลี่ยได้ ด้วยหลักการของ PWM ซึ่งเมื่อเราเปลี่ยนแปลงค่า %duty cycle แล้วจะทำให้เสมือนว่า แรงดันเฉลี่ยที่ออกมาดูเหมือนเปลี่ยนแปลงตามไปด้วย ด้วยผลลัพธ์นี้ เมื่อเรานำมาขับหลอด LED เราจะเห็นว่า หลอด LED ดูเหมือน สว่างมาก สว่างน้อย ตามการเปลี่ยนเปลงของ %duty cycle

จากหลักการนี้ เมื่อนำมารวมกับการเขียนโปรแกรมให้ไฟวิ่ง โดยให้หลอดไฟมีการไล่วงจรการติดดับเรียงลำดับกันไป คุณก็จะได้ วงจรไฟวิ่งฝนดาวตก อย่างง่ายๆ แล้วหล่ะครับ ซึ่งถ้าจะทำเป็นการค้าจริงๆ อาจจะต้องพิจารณาหลายอย่างเหมือนกัน แต่ว่าทำเอาไว้ให้แฟนดูในห้องกันสองคน จะภูมิใจกว่าหน่ะครับ อิอิอิ

ชมตัวอย่างงานที่เค้าทำขายกันจริงๆ จากคลิปวีดีโอครับ

วิดีโอ YouTube


มาเริ่มกันเลยดีกว่า ที่บอร์ด Arduino จะมีขา digital out ที่เป็น PWM ให้เรา 6 pin ครับ ไ้ด้แก่ PIN 11,10,9,6,5,3 ดูจากรูปด้านล่าง เราก็เอาหลอด LED ต่อที่ขาดังกล่าวเลยครับ โดยเรียนลำดับขาตาม ลำดับหมายเลข PIN นะครับ เพื่อเวลาที่โปรแกรมทำงาน ไฟจะได้ติดดับตามลำดับ ที่เราออกแบบไว้ที่โค๊ด หน่ะครับ

ในส่วนของโค๊ด ผมได้ศึกษาจากโค๊ดตัวอย่างเรื่อง Fading แล้วก็มาประยุกต๋เอาครับ ในที่นี้ ผมได้ต่อที่หลอด LED เข้าที่ขา PIN PWM ทั้ง 6 PIN
โดยกำหนดให้ ลำดับการต่อหลอด LED เรียงตามลำดับ PIN PWM ของ Arduino

ต่อมา ผมก็มานั่งคิดตารางการเรียงลำดับการไหลของ ไฟวิ่งฝนดาวตก ก่อนครับ แต่ถ้าใครคิดในหัวออกได้ ก็ตามใจครับ ค่าที่กำหนดได้สูงสุด ไม่เกิน 255 นะครับ เพราะที่ขา PWM นี้ มีความละเอียดแค่ 8 บิต ครับ ( 2^8 = 256 ไม่คิดเครื่องหมาย)



โค๊ด Arduino ไฟวิ่งฝนดาวตก (พอดี เขียนตอนดึก คิดได้ประมาณนี้ เพื่อนๆ อาจจะคิดได้ไม่เหมือนผมนะครับ อย่าซีเรียส)

int ledArr[] = {11,10,9,6,5,3}; // Led0 ..... Led5
void setup(){ }

void loop()
{
  for(int i = 0 ; i <13; i++){
    if(i<6){
      analogWrite(ledArr[i],255);// forward
      for(int k=0;k<i;k++){
        analogWrite(ledArr[k],fadeArr[i-k]); //update previous
      }
    }else{
      for(int j=0;j<6;j++){
        analogWrite(ledArr[j],fadeArr[i-j]); // update previous
      }     
    }   
    delay(100);   
  } 
}



Arduino ไฟวิ่งฝนดาวตก


 
 
พอดีผมแก้โค๊ดให้วิ่งกลับไปกลับมา ในวีดีโอจึงแสดงแบบนั้น

int fadeArr[] = {255, 200, 150, 100, 50, 10, 0, 0, 0, 0, 0, 0, 0};
int ledArr_fwd[] = {11,10,9,6,5,3}; // Led0 ..... Led5
int ledArr_rwd[] = {3,5,6,9,10,11}; // Led5 ..... Led0
int dl = 100;
void setup(){ }

void loop()
{
  for(int i = 0 ; i <13; i++){
    if(i<6){
      analogWrite(ledArr_fwd[i],255);// forward
      for(int k=0;k<i;k++){
        analogWrite(ledArr_fwd[k],fadeArr[i-k]); //update previous
      }
    }else{
      //analogWrite(ledArr[i-1],fadeArr[i-k]);// forward
      for(int j=0;j<6;j++){
        analogWrite(ledArr_fwd[j],fadeArr[i-j]); // update previous
      }     
    }   
    delay(dl);   
  }
  delay(300);
  for(int i = 0 ; i <13; i++){
    if(i<6){
      analogWrite(ledArr_rwd[i],255);// forward
      for(int k=0;k<i;k++){
        analogWrite(ledArr_rwd[k],fadeArr[i-k]); //update previous
      }
    }else{
      for(int j=0;j<6;j++){
        analogWrite(ledArr_rwd[j],fadeArr[i-j]); // update previous
      }     
    }   
    delay(dl);   
  } 
}

ไมโครคอนโทรลเลอร์รับตัวอักษรผ่าน RS232

โพสต์10 ก.พ. 2554 03:22โดยวิสิทธิ์ แผ้วกระโทก   [ อัปเดต 18 ม.ค. 2557 07:20 ]

Microcontroller C Code Sample

ไมโครคอนโทรลเลอร์รับตัวอักษรผ่าน RS232

โค๊ดตัวอย่างการรับค่า String คอมพิวเตอร์ส่งไปที่ไมโครคอนโทรลเลอร์ ผ่าน RS232 

    การสื่อสารระหว่างไมโครคอนโทรลเลอร์ กับคอมพิวเตอร์ ด้วย RS232 ยังเป็นที่นิยม เนื่องจากเป็นโปรโตคอลที่ง่าย และสะดวกรวดเร็ว เนื่องจากรับส่งข้อมูลที่ไม่ต้องการปริมาณมากๆ บ่อยครั้งที่เรามักจะใช้ RS232 ในการส่งคำสั่งบางอย่างลงไปที่ไมโครคอนโทรลเลอร์ เพื่อให้ไมโครคอนโทรลเลอร์ทำงานตามคำสั่งบางอย่างให้กับเรา

     ตัวอย่างต่อไปนี้ เป็นการติดต่อสื่อสารระหว่างไมโครคอนโทรลเลอร์ และคอมพิวเตอร์ ผ่าน RS232 โดยใช้ interrupt 
ของไมโครคอนโทรลเลอร์เป็นตัวคอยเช็คว่ามีข้อมูลถูกส่งมาจากคอมพิวเตอร์หรือยัง

Function name : void get_string(char* s, unsigned int8 max)
Complier : CCS C Complier
Purpose : Recieve data from RS232 protocal by interrupt

/*--------------------- get string from RS232 -----------------------------*/
void get_string(char* s, unsigned int8 max) {
   unsigned int8 len;
   char c;

   --max;
   len=0;
   do {
     c=getc();
     if(c==8) {  // Backspace
        if(len>0) {
          len--;
          //putc(c);
          //putc(' ');
          //putc(c);
        }
     } else if ((c>=' ')&&(c<='~'))
       if(len<=max) {
         s[len++]=c;
         //putc(c);
       }
   } while(c!=13);
   s[len]=0;
}

 
 

การประยุกต์ใช้งาน 
ตัวอย่างต่อไปนี้ เป็นการแสดงการรับส่งข้อมูลจากคอมพิวเตอร์ ผ่านพอร์ตอนุกรม โดยส่งข้อความไปที่ไมโครคอนโทรลเลอร์ผ่าน RS232 โดยในการสาธิตนี้ เราได้ทำการจำลองการทำงานผ่านโปรแกรม Proteus และใช้โปรแกรม Virtual Serial Port Emulator เมื่อทำการเชื่อมต่อพอร์ตอนุกรม ได้แล้ว จึงทำการส่งข้อมูลที่เป็นตัวอักษรผ่าน Hyper Terminal ของโปรแกรม Windows 



โค๊ด main ของโปรเจค
#include <16F877.h> 

// Configuration 
#fuses NOWDT,HS, NOPUT, NOPROTECT,NOLVP,BROWNOUT
#use delay (clock=10000000)   // Crystal 10MHz
#define  TxD         PIN_C6   // Define Transmitted Data
#define  RxD         PIN_C7   // Define Received Data
#use rs232(baud=9600, xmit=TxD,rcv=RxD,stream=PC_COM) // Use serial I/O port (RS232)

//External library
#include "lcd1.c"

// Global variables
#define  STRING_SIZE    6   // The number of characters allowed to input
char input_str[STRING_SIZE];
BOOLEAN extREQ = FALSE;


// Function prototype
void get_string(char* s, unsigned int8 max);


// Interrupt service routine
#int_rda
void rs232_isr()
{
   get_string(input_str,STRING_SIZE);     // gets the string
   extREQ = TRUE;
}

// ========================  Main ====================================//
void main(void)
{
enable_interrupts(INT_RDA);               // Enable interrupt RS232 recieve data
enable_interrupts(GLOBAL);   
lcd_init();
delay_ms(1000);
printf(lcd_putc,"\fRS232 Simple\n");
lcd_putc(".........By Mr.P");
delay_ms(1000);
while(TRUE)
{
lcd_gotoxy(1,1);  printf(lcd_putc,"Waiting for cmd ",);
if(extREQ)
{
lcd_gotoxy(1,1);  printf(lcd_putc,"\fyou put string");
lcd_gotoxy(1,2);  printf(lcd_putc,"%s",input_str);
delay_ms(1000);
extREQ = FALSE;
lcd_gotoxy(1,2);  printf(lcd_putc,"                ");
}
}
}



/*--------------------- get string from RS232 -----------------------------*/
void get_string(char* s, unsigned int8 max) {
   unsigned int8 len;
   char c;

   --max;
   len=0;
   do {
     c=getc();
     if(c==8) {  // Backspace
        if(len>0) {
          len--;
          putc(c);
          putc(' ');
          putc(c);
        }
     } else if ((c>=' ')&&(c<='~'))
       if(len<=max) {
         s[len++]=c;
         putc(c);
       }
   } while(c!=13);
   s[len]=0;
}


คลิปวีดีโอสาธิตการส่งข้อมูลผ่าน RS232 กับ PIC16F877


อย่าลืมดาวน์โหลดไฟล์ lcd1.c ที่แนบไว้นี้ เข้าไปไว้ที่เดียวกันกับในโฟวเดอร์ซอร์สไฟล์ของเราด้วยครับ 

CCS C Library Code : LCD 20x4 Driver

โพสต์2 ก.พ. 2554 17:35โดยวิสิทธิ์ แผ้วกระโทก   [ อัปเดต 18 ม.ค. 2557 07:20 ]

Microcontroller C Code Sample

CCS C Library Code : LCD 20x4 Driver

โค๊ดไลบรารี่สำหรับขับจอ LCD ขนาด 20 ตัวอักษร จำนวน 4 บรรทัด 


File : Flex_LCD420.c
Complier : CCS C Complier
Purpose : Driver LCD 20 x 4 

การใช้งาน 
  1. คัดลอกโค๊ดนี้ บันทึุกไฟล์เป็น Flex_LCD420.c
  2. ทำการประกาศ #include <Flex_LCD420.c> ใน file ที่เป็น main function ของโปรเจค
  3. ทำการเรียกฟังก์ชัน lcd_init(); ก่อน โดยเอาไว้บรรทัดก่อนมีการเรียกใช้่ เพื่อทำการ Initial LCD ก่อนการใช้งาน
  4. แล้วทำการเรียกใช้ฟังก์ชันการส่งตัวอักษรผ่านฟังก์ชัน 
    1. lcd_gotoxy(1, 2); เป็นการระบุตำแหน่งเริ่มต้นการส่งตัวอักษร ตำแหน่งที่ 1 บรรทัดที่่ 2
    2. printf(lcd_putc,"%2X",value);  ส่งค่า value ให้ไปแสดงเป็นตัวเลข Hex

 
 



// Flex_LCD420.c 

// These pins are for my Microchip PicDem2-Plus board, 
// which I used to test this driver. 
// An external 20x4 LCD is connected to these pins. 
// Change these pins to match your own board's connections. 

#define LCD_DB4   PIN_B3 
#define LCD_DB5   PIN_B4 
#define LCD_DB6   PIN_B6 
#define LCD_DB7   PIN_B7 

#define LCD_RS    PIN_E0 
#define LCD_RW    PIN_E1 
#define LCD_E     PIN_E2 

/* 
// To prove that the driver can be used with random 
// pins, I also tested it with these pins: 
#define LCD_DB4   PIN_D4 
#define LCD_DB5   PIN_B1 
#define LCD_DB6   PIN_C5 
#define LCD_DB7   PIN_B5 

#define LCD_RS    PIN_E2 
#define LCD_RW    PIN_B2 
#define LCD_E     PIN_D6 
*/ 

// If you want only a 6-pin interface to your LCD, then 
// connect the R/W pin on the LCD to ground, and comment 
// out the following line.  Doing so will save one PIC 
// pin, but at the cost of losing the ability to read from 
// the LCD.  It also makes the write time a little longer 
// because a static delay must be used, instead of polling 
// the LCD's busy bit.  Normally a 6-pin interface is only 
// used if you are running out of PIC pins, and you need 
// to use as few as possible for the LCD. 
#define USE_RW_PIN   1      


// These are the line addresses for most 4x20 LCDs. 
#define LCD_LINE_1_ADDRESS 0x00 
#define LCD_LINE_2_ADDRESS 0x40 
#define LCD_LINE_3_ADDRESS 0x14 
#define LCD_LINE_4_ADDRESS 0x54 

// These are the line addresses for LCD's which use 
// the Hitachi HD66712U controller chip. 
/* 
#define LCD_LINE_1_ADDRESS 0x00 
#define LCD_LINE_2_ADDRESS 0x20 
#define LCD_LINE_3_ADDRESS 0x40 
#define LCD_LINE_4_ADDRESS 0x60 
*/ 


//======================================== 

#define lcd_type 2   // 0=5x7, 1=5x10, 2=2 lines(or more) 

int8 lcd_line; 

int8 const LCD_INIT_STRING[4] = 
 0x20 | (lcd_type << 2),  // Set mode: 4-bit, 2+ lines, 5x8 dots 
 0xc,                     // Display on 
 1,                       // Clear display 
 6                        // Increment cursor 
 }; 
                              

//------------------------------------- 
void lcd_send_nibble(int8 nibble) 
// Note:  !! converts an integer expression 
// to a boolean (1 or 0). 
 output_bit(LCD_DB4, !!(nibble & 1)); 
 output_bit(LCD_DB5, !!(nibble & 2));  
 output_bit(LCD_DB6, !!(nibble & 4));    
 output_bit(LCD_DB7, !!(nibble & 8));    

 delay_cycles(1); 
 output_high(LCD_E); 
 delay_us(2); 
 output_low(LCD_E); 

//----------------------------------- 
// This sub-routine is only called by lcd_read_byte(). 
// It's not a stand-alone routine.  For example, the 
// R/W signal is set high by lcd_read_byte() before 
// this routine is called.      

#ifdef USE_RW_PIN 
int8 lcd_read_nibble(void) 
int8 retval; 
// Create bit variables so that we can easily set 
// individual bits in the retval variable. 
#bit retval_0 = retval.0 
#bit retval_1 = retval.1 
#bit retval_2 = retval.2 
#bit retval_3 = retval.3 

retval = 0; 
    
output_high(LCD_E); 
delay_us(1); 

retval_0 = input(LCD_DB4); 
retval_1 = input(LCD_DB5); 
retval_2 = input(LCD_DB6); 
retval_3 = input(LCD_DB7); 
  
output_low(LCD_E); 
delay_us(1); 
    
return(retval);    
}    
#endif 

//--------------------------------------- 
// Read a byte from the LCD and return it. 

#ifdef USE_RW_PIN 
int8 lcd_read_byte(void) 
int8 low; 
int8 high; 

output_high(LCD_RW); 
delay_cycles(1); 

high = lcd_read_nibble(); 

low = lcd_read_nibble(); 

return( (high<<4) | low); 
#endif 

//---------------------------------------- 
// Send a byte to the LCD. 
void lcd_send_byte(int8 address, int8 n) 
output_low(LCD_RS); 

#ifdef USE_RW_PIN 
while(bit_test(lcd_read_byte(),7)) ; 
#else 
delay_us(60);  
#endif 

if(address) 
   output_high(LCD_RS); 
else 
   output_low(LCD_RS); 
      
 delay_cycles(1); 

#ifdef USE_RW_PIN 
output_low(LCD_RW); 
delay_cycles(1); 
#endif 

output_low(LCD_E); 

lcd_send_nibble(n >> 4); 
lcd_send_nibble(n & 0xf); 
//---------------------------- 

void lcd_init(void) 
   int8 i; 

   lcd_line = 1; 

   output_low(LCD_RS); 

   #ifdef USE_RW_PIN 
      output_low(LCD_RW); 
   #endif 

   output_low(LCD_E); 

   // Some LCDs require 15 ms minimum delay after 
   // power-up.  Others require 30 ms.  I'm going 
   // to set it to 35 ms, so it should work with 
   // all of them. 
   delay_ms(35);          

   for(i=0 ;i < 3; i++) 
   { 
      lcd_send_nibble(0x03); 
      delay_ms(5); 
   } 

   lcd_send_nibble(0x02); 

   for(i=0; i < sizeof(LCD_INIT_STRING); i++) 
   { 
      lcd_send_byte(0, LCD_INIT_STRING[i]); 
    
      // If the R/W signal is not used, then 
      // the busy bit can't be polled.  One of 
      // the init commands takes longer than 
      // the hard-coded delay of 50 us, so in 
      // that case, lets just do a 5 ms delay 
      // after all four of them. 
      #ifndef USE_RW_PIN 
         delay_ms(5); 
      #endif 
   } 


//---------------------------- 

void lcd_gotoxy(int8 x, int8 y) 
int8 address; 


switch(y) 
  { 
   case 1: 
     address = LCD_LINE_1_ADDRESS; 
     break; 

   case 2: 
     address = LCD_LINE_2_ADDRESS; 
     break; 

   case 3: 
     address = LCD_LINE_3_ADDRESS; 
     break; 

   case 4: 
     address = LCD_LINE_4_ADDRESS; 
     break; 

   default: 
     address = LCD_LINE_1_ADDRESS; 
     break; 
      
  } 

address += x-1; 
lcd_send_byte(0, 0x80 | address); 

//----------------------------- 
void lcd_putc(char c) 
 switch(c) 
   { 
    case '\f': 
      lcd_send_byte(0,1); 
      lcd_line = 1; 
      delay_ms(2); 
      break; 
    
    case '\n': 
       lcd_gotoxy(1, ++lcd_line); 
       break; 
    
    case '\b': 
       lcd_send_byte(0,0x10); 
       break; 
    
    default: 
       lcd_send_byte(1,c); 
       break; 
   } 

//------------------------------ 
#ifdef USE_RW_PIN 
char lcd_getc(int8 x, int8 y) 
char value; 

lcd_gotoxy(x,y); 

// Wait until busy flag is low. 
while(bit_test(lcd_read_byte(),7));  

output_high(LCD_RS); 
value = lcd_read_byte(); 
output_low(LCD_RS); 

return(value); 
#endif 


ให้เพื่อนทดสอบ ลองเปลี่ยนขาที่ต่อกับ LCD โดยแก้ไขโค๊ดใน Flex_LCD420.c ในที่นี้ผมลองแก้คอมเม้นต์ออก เพิ่อทดสอบการย้ายขาไมโคร ว่าจะต่อได้หมดทุกขาไหม โดยแก้ไขเป็น

#define LCD_DB4   PIN_D4 
#define LCD_DB5   PIN_B1 
#define LCD_DB6   PIN_C5 
#define LCD_DB7   PIN_B5 

#define LCD_RS    PIN_E2 
#define LCD_RW    PIN_B2 
#define LCD_E     PIN_D6 

่ผลทดลอง 
#include <16f877a.h>

#fuses HS,NOWDT,NOLVP,NOBROWNOUT
#use delay(clock=20M)

#include "Flex_LCD420.c"
void main(void)
{
    lcd_init();
    delay_ms(200);
    while(TRUE)
    {
      lcd_gotoxy(1,1);
      lcd_putc("Hello World");
      lcd_gotoxy(1,2);
      lcd_putc("Test mix port");      
    }

}


เครดิต : PCM programmer
http://www.ccsinfo.com/forum/viewtopic.php?t=28268

7 segment + Interrupt timer0 นับเลขง่ายๆ ด้วย Hi-tech C

โพสต์17 ม.ค. 2554 08:38โดยวิสิทธิ์ แผ้วกระโทก   [ อัปเดต 18 ม.ค. 2557 07:18 ]

Microcontroller C Code Sample


7 segment + Interrupt timer0 นับเลขง่ายๆ ด้วย Hi-tech C

วันนี้ ผมขอเสนอวิธีการเขียนโค๊ดด้วยภาษาซี ด้วยคอมไพล์เลอร์ Hi-tech C กับบอร์ดที่ผมมีอยู่ ซึ่งเป็นบอร์ด BasePicR2 ที่ผมมีอยู่ ซึ่งบนบอร์ดตัวนี้ ผมได้ใส่ไมโครคอนโทรลเลอร์ เบอร์ PIC16F877 ในการส่งตัวเลขแสดงออกทาง 7-segment จำนวนสี่หลัก โดยให้ตัวเลขเพิ่มค่าขึ้นเรื่อยๆ โดยเปลี่ยนแปลงค่าโดยใช้ค่าเวลาจาก Timer0 ( 8 บิต) เป็นโค๊ดง่ายๆ เพื่อให้เพื่อนๆ ลองเอาไปประยุกต์ใช้งานกันครับ 

วงจร

แนวทางการออกแบบ
1. กำหนดค่า register ที่เกี่ยวข้องกับ Timer0 เำืพื่อให้ Timer0 ทำหน้าที่เป็น Timer
2. สร้าง Interrupt service routine เพื่อให้โปรแกรมกระโดดเข้ามาทำงานเมื่อ Timer0 เกิด Interrupt เนื่องจาก Overflow 
3. ดึงค่าที่ถูกเปลี่ยนแปลงจาก Interrupt routine เข้ามาแสดงผลในส่วนของฟังก์ชั่น main ซึงทำหน้าที่วนลูปไปเรื่อยๆ 
4. ค่าที่ถูกแสดงถูกหารเอาเศษ และหารแบบเลขจำนวนเต็ม เพื่อนำไปชี้ค่าใน Array ที่เป็นส่วนที่แสดงผลของ 7-segment เืพื่อให้ตัวเลขติด


โค๊ด 

#include <htc.h>
#define _XTAL_FREQ 20000000

__CONFIG(FOSC_HS & LVP_OFF & WDTE_OFF & PWRTE_OFF & BOREN_OFF);

void iniTimer0(void);

unsigned char _7Segment[16] = {0x3F,0x06,0x5B,0x4F,0x66,    //0,1,2,3,4
                   0x6D,0x7D,0x07,0x7F,0x6F,    //5,6,7,8,9
                   0x77,0x7C,0x39,0x5E,0x79,    //A,b,C,d,E
                   0x71};                       //F
                   
unsigned char num[4] = {0x08,0x04,0x02,0x01}; 
unsigned int count;
unsigned int ms;

void interrupt TIMER0_INT(void)
{
if(T0IF)  // TMR0 Overflow Interrupt Flag bit
{
TMR0 = 216;
T0IF = 0; // reset TMR0 Overflow Interrupt Flag bit
ms++;
if(ms >= 100)
{
count = (count >9999)?0:count++;
ms = 0;
}
}
}

void main(void)
{
unsigned int time = 1;
ADCON1 |= 0x06; // all pin A is digital 
TRISB = 0x00;
TRISA &= 0b11100000;
PORTB = 0x00;
PORTA = 0x00;
GIE = 1; //Global Interrupt Enable
iniTimer0();
while(1)
{
PORTB = _7Segment[((count%1000)%100)%10];
PORTA = num[0];
PORTB = _7Segment[((count%1000)%100)/10];
PORTA = num[1];
PORTB = _7Segment[(count%1000)/100];
PORTA = num[2];
PORTB = _7Segment[count/1000];
PORTA = num[3];
}

}

void iniTimer0(void)
{
T0CS = 0; // use timer0 in timer mode.
PS0 = 0;  // prescaler 1:128
PS1 = 1;
PS2 = 1; 
PSA = 0;  //Prescaler is assigned to the Timer0
TMR0 = 216; // 234 
T0IF = 0;
T0IE = 1; // Enables the TMR0 interrupt
}

วีดีโอสาธิต 

1-5 of 5