Hiển thị các bài đăng có nhãn code điện tử. Hiển thị tất cả bài đăng
Hiển thị các bài đăng có nhãn code điện tử. Hiển thị tất cả bài đăng

Thứ Tư, 23 tháng 7, 2014

Thứ Tư, 24 tháng 10, 2012

Code mẫu cho PIC - Truyền thông nối tiếp RS232

Việc giao tiếp giữa Vi điều khiển và máy tính là bài lập trình khá quan trọng khi ta làm việc với các dòng Vi điều khiển khác nhau. Với Vi điều khiển PIC cũng vậy, trong mỗi IC PIC đều có tích hợp một khối giao tiếp máy tính USART. Ta sử dụng khối giao tiếp này để truyền dữ liệu lên máy tính và xử lý dữ liệu đó tùy vào mục đích của người lập trình. Để nhận dữ liệu do Vi điều khiển truyền lên máy tính ta có thể sử dụng các phần mềm giao tiếp COM có sẵn hay viết một chương trình mới, sử dụng các ngôn ngữ lập trình như C++, VB hay Delphi… Trong chương trình ví dụ dưới đây tôi sử dụng công cụ sẵn có của CCS là Serial Port Monitor để truyền và nhận dữ liệu từ PIC.

Sơ đồ mạch điện ORCAD. Mạch sử dụng IC MAX232 để kết nối đến cổng COM của
máy tính. Mạch đơn giản chỉ nhằm mục đích giới thiệu khối giao tiếp máy tính của PIC và
cách lập trình cho nó trong CCS.


Trong chương trình ta có sử dụng hàm xử lý ngắt nối tiếp để xử lý ký tự nhân được từ máy
tính. Khi có ngắt xảy ra, ta gọi hàm getc() sẽ trả về ký tự vừa nhận được. Trên màn hình LCD
sẽ hiển thị ký tự mà ta gõ từ bàn phím máy tính.



Mạch giao tiếp máy tính, hiển thị LCD



Mã nguồn chương trình:


#include <16f877a.h>
#include <def_877a.h>
#use delay(clock=20000000)
#FUSES NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT,
NOLVP, NOCPD, NOWRT
// Khai báo sử dụng giao tiếp nối tiếp RS232
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9)


#include <lcd_lib_4bit.c>


int8 count=0;
char string_in[16];


#INT_RDA // Hàm xử lý ngắt nối tiếp
Receive_isr() {
char c;
int8 i;
count++;
c = getc();
putc(c);
if (c==ʹcʹ | c==ʹCʹ)
{
LCD_putcmd(0x01); //Clear Screen
c=ʹcʹ;
count=0;
}
if ((count<=16) && (c!=ʹcʹ)) LCD_putchar(c);
if (count > 16)
{
count=0;
LCD_putcmd(0xC0);
}
}
void main()
{

enable_interrupts(int_rda);
enable_interrupts(GLOBAL);

lcd_init(); // Khởi tạo cho LCD
lcd_putcmd(0x01);
lcd_putcmd(line_1);
printf(ʺEnter a String.ʺ);
printf(ʺOr anything you want!ʺ);
while (1) {}
}


Mô tả chương trình: Trên đây là chương trình giao tiếp với máy tính, ta thấy trong CCS để sử dụng giao tiếp nối tiếp ta chỉ cần khai báo #use rs232(). Các hàm giao tiếp với máy tính mà CCS hỗ trợ là:
‐ putc(char ky_tu) : Gửi một ký tự ASCII lên máy tính
‐ getc() : Hàm trả về một ký tự nhận được từ máy tính
‐ printf(string): hàm gửi một chuỗi ký tự lên máy tính


[Lập trình PIC] Truyền Thông Nối Tiếp RS232 - Xử Lý Chuỗi Trong CCS

+ Phần này sẽ giúp bạn viết chương trình có sử dụng giao tiếp với máy tính (PC) . Điều này rất cần thiết khi bạn muốn VĐK khi hoạt động có thể truyền dữ liệu cho PC xử lý , hoặc nhận giá trị từ PC để xử lý và điều khiển ( dùng PC điều khiển động cơ , nhiệt độ , hay biến PC thành dụng cụ đo các đại lượng điện, Oscilocope , . . .) .
+ Viết chương trình lập trình cho VĐK để giao tiếp máy tính là công việc rất phức tạp khi viết bằng ASM , rất khó hiểu đối với những người mới bắt đầu lập trình . Đặc biệt là khi viết cho những con VĐK không hỗ trợ từ phần cứng ( 8951 thì phải (?) ) . Thật may là phần lớn PIC hiện nay đều hỗ trợ phần này nên việc lập trình có dễ dàng hơn . Nhưng nếu chương trình của bạn yêu cầu truyền hay nhận nhiều loại dữ liệu ( số 8 , 16 ,32 bit , dương , âm , chuỗi , . . .) thì việc viết chương trình xử lý và phân loại chúng là điều “ kinh dị “ .



+ Nếu bạn đã lập trình ASM cho vấn đề này rồi thì bạn sẽ thấy sao dễ dàng quá vậy khi giải quyết vấn đề này với C khi dùng CCS . Rất đơn giản ! CCS cung cấp rất nhiều hàm phục vụ cho giao tiếp qua cổng COM và vô số hàm xử lý chuỗi . Chương này sẽ giải quyết điều đó .
+ Một yếu tố quan trọng là khi nào thì VĐK biết PC truyền data => có thể lập trình bắt tay bằng phần mềm hay đơn giản là dùng ngắt . Các ví dụ về ngắt , xem phần ngắt .




I / TRUYỀN THÔNG VỚI PC QUA CỔNG COM :
+ Để sử dụng giao thức này , phải có 2 khai báo như ví dụ sau :
#use delay (clock = 40000000 ) // nếu VDK đang dùng OSC 40Mhz
#use rs232 (baud=19200 , parity=n , xmit=pin_C6 , rcv=pin_C7 )
// baud= 19200 , không chẵn lẻ , chân truyền C6 , chân nhận C7


+Các hàm liên quan :
Printf ( )
Getc ( ) putc ( )
Getch ( ) putchar ( )
Getchar ( ) fputc ( )
Fgetc ( ) puts ( )
Gets ( ) fputs ( )
Fgets ( )
Kbhit ( )
Assert ( ) => mới trên CCS 3.222
Perror ( ) => mới trên CCS 3.222
Set_uart_speed ( )
Setup_uart ( )



+ Tất cả các hàm trên đòi hỏi phải khai báo chỉ thị tiền xử lý #use RS232 ( . . . . .) . Chi tiết chỉ thị này xem phần Chỉ thị tiền xử lý .
+ Hàm perror ( ) đòi hỏi thêm #include<errno.h > . Hàm assert() đòi hỏi thêm #include<assert.h> .


1 / printf ( string )
Printf ( cstring , values . . . )
+ Dùng xuất chuỗi theo chuẩn RS232 ra PC .
+ string là 1 chuỗi hằng hay 1 mảng ký tự ( kết thúc bởi ký tự null ) .
+ value là danh sách các biến , cách nhau bởi dấu phẩy .
+ Bạn phải khai báo dạng format của value theo kiểu %wt .Trong đó w có thể có hoặc không, có giá trị từ 1-9 chỉ rõ có bao nhiêu ký tự được xuất ra ( mặc định không có thì có bao nhiêu ra bấy nhiêu ), hoặc 01-09 sẽ chèn thêm 0 cho đủ ký tự hoặc 1.1-1.9 cho trường hợp số thực . còn t là kiểu giá trị .
+ t có thể là :
C : 1 ký tự
S : chuỗi hoặc ký tự
U : số 8 bit không dấu
x : số 8 bit kiểu hex ( ký tự viết thường ,VD : 1ef )
X : số 8 bit kiểu hex ( ký tự viết hoa ,VD : 1EF )
D : số 8 bit có dấu
e : số thực có luỹ thừa VD : e12

f : số thực
Lx : số hex 16 /32 bit ( ký tự viết thường )
LX : hex 16 /32 bit ( ký tự viết hoa )
Lu : số thập phân không dấu
Ld : số thập phân có dấu
% : ký hiệu %
VD :
Specifier Value=0x12 Value=0xfe
%03u 018 254
%u 18 254
%2u 18 *
%5 18 254
%d 18 -2
%x 12 Fe
%X 12 FE
%4X 0012 00FE
* Result is undefined - Assume garbage.
VD :
Int k =6 ;
Printf ( “ hello “ );
Printf ( “ %u “ , k );


2 / KBHIT ( ) :
+ Thường thì chúng ta dùng RC6 và RC7 cho RX và TX trong giao tiếp cổng COM , VDK PIC trang bị phần cứng phục vụ việc này với thanh ghi gởi và nhận và các bit bào hiệu tương ứng . Do đó khi dùng RS232 hỗ trợ từ phần cứng thì KHBIT ( ) trả về TRUE nếu 1 ký tự đã được nhận ( trong bộ đệm phần cứng ) và sẵn sàng cho việc đọc , và trả về 0 nếu chưa sẵn sàng .
+ Hàm này có thể dùng hỏi vòng xem khi nào có data nhận từ RS232 để đọc .


Nguồn : TRẦN XUÂN TRƯỜNG

Code mẫu PIC - Giao Tiếp I2C Với IC Thời gian thực DS1307

Chương trình thực hiện giao tiếp I2C giữa PIC 16F877A và IC DS1307 để cài đặt thời gian, đọc thời gian từ DS1307, hiển thị lên LCD, truyền qua RS232.
Với LCD, chương trình sẽ đọc dữ liệu DS1307 và cập nhật LCD liên tục, còn khi truyền lên máy tính sẽ dựa vào ngắt RB0 đưa vào từ xung 1Hz của DS1307, tức là mỗi 1s sẽ truyền dữ liệu 1 lần.
Trong chương trình có sử dụng các thư viện: lcd_lib_4bit.c, ds1307.c.

Sơ đồ nguyên lý mô phỏng trên Proteus:







Truyền lên hyper terminal:





Mã nguồn chương trình chính:



#include "16f877a.h"
#include "def_877a.h"


#device *=16 ADC=10
#use delay(clock=20000000)
#FUSES NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use i2c(Master, sda = PIN_C4, scl=PIN_C3)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)


#include "lcd_lib_4bit.c"
#include "ds1307.c"


#define Slave_add 0x68
#define Read 1
#define Write 0


void send(int8 a);


int8 sec,min,hrs,day,month,yr,dow;


//ngat o chan RB0: Truyen len cong RS232
#int_EXT
void EXT_isr(void) //moi 1s truyen len may tinh 1 lan
{
ds1307_get_date(day,month,yr,dow);
ds1307_get_time(hrs,min,sec);
send(hrs);
putc(45);
send(min);
putc(45);
send(sec);
putc(10);
return;
}
void main()
{
enable_interrupts(INT_EXT);//cho phep ngat RB0
ext_int_edge(0,H_TO_L);//dat suon ngat
enable_interrupts(GLOBAL);//cho phep ngat toan cuc

LCD_init(); //Khoi tao LCD.
delay_ms(10);
ds1307_init();// khoi tao DS1307, tao xung 1Hz o chan 7 DS1307.
// Set date : 12-4-2012
// Set time : thu 5 - 12 gio, 59 phút 10 giây
ds1307_set_date_time(12,4,12,5,12,59,10);



while(1)
{
ds1307_get_date(day,month,yr,dow);
ds1307_get_time(hrs,min,sec);

//Truyen len LCD
//o day chi hien gio, phut, giay. cac thong tin khac thuc hien tuong tu.
LCD_PutCmd(0x80);
LCD_PutChar(hrs/10+48);
LCD_PutChar(hrs%10+48);
LCD_PutChar(45);
LCD_PutChar(min/10+48);
LCD_PutChar(min%10+48);
LCD_PutChar(45);
LCD_PutChar(sec/10+48);
LCD_PutChar(sec%10+48);
}
}
void send(int8 a)
{
if(a<10)
{
putc(a+48);
}
if(a>9&&a<100)
{
unsigned char c=a/10;
unsigned char d=a%10;
putc(c+48);
putc(d+48);
}
if(a>99)
{
unsigned char t=a/100;
unsigned char c=a/10-10*t;
unsigned char d=a%10;
putc(t+48);
putc(c+48);
putc(d+48);
}
}


Thư viện lcd_lib_4bit.c:


#include <stddef.h>

#define LCD_RS PIN_D2
//#define LCD_RW PIN_A1
#define LCD_EN PIN_D3


#define LCD_D4 PIN_D4
#define LCD_D5 PIN_D5
#define LCD_D6 PIN_D6
#define LCD_D7 PIN_D7


// misc display defines-
#define Line_1 0x80
#define Line_2 0xC0
#define Clear_Scr 0x01


// prototype statements
#separate void LCD_Init ( void );// ham khoi tao LCD
#separate void LCD_SetPosition ( unsigned int cX );//Thiet lap vi tri con tro
#separate void LCD_PutChar ( unsigned int cX );// Ham viet1kitu/1chuoi len LCD
#separate void LCD_PutCmd ( unsigned int cX) ;// Ham gui lenh len LCD
#separate void LCD_PulseEnable ( void );// Xung kich hoat
#separate void LCD_SetData ( unsigned int cX );// Dat du lieu len chan Data
// D/n Cong
#use standard_io (C)
#use standard_io (D)


//khoi tao LCD**********************************************

#separate void LCD_Init ( void )
{
LCD_SetData ( 0x00 );
delay_ms(200); /* wait enough time after Vdd rise >> 15ms */
output_low ( LCD_RS );// che do gui lenh
LCD_SetData ( 0x03 ); /* init with specific nibbles to start 4-bit mode */
LCD_PulseEnable();
LCD_PulseEnable();
LCD_PulseEnable();
LCD_SetData ( 0x02 ); /* set 4-bit interface */
LCD_PulseEnable(); /* send dual nibbles hereafter, MSN first */
LCD_PutCmd ( 0x2C ); /* function set (all lines, 5x7 characters) */
LCD_PutCmd ( 0x0C ); /* display ON, cursor off, no blink */
LCD_PutCmd ( 0x06 ); /* entry mode set, increment & scroll left */
LCD_PutCmd ( 0x01 ); /* clear display */
}


#separate void LCD_SetPosition ( unsigned int cX )
{
/* this subroutine works specifically for 4-bit Port A */
LCD_SetData ( swap ( cX ) | 0x08 );
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) );
LCD_PulseEnable();
}


#separate void LCD_PutChar ( unsigned int cX )
{
/* this subroutine works specifically for 4-bit Port A */
output_high ( LCD_RS );
LCD_PutCmd( cX );
output_low ( LCD_RS );
}


#separate void LCD_PutCmd ( unsigned int cX )
{
/* this subroutine works specifically for 4-bit Port A */
LCD_SetData ( swap ( cX ) ); /* send high nibble */
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) ); /* send low nibble */
LCD_PulseEnable();
}
#separate void LCD_PulseEnable ( void )
{
output_high ( LCD_EN );
delay_us ( 3 ); // was 10
output_low ( LCD_EN );
delay_ms ( 3 ); // was 5
}


#separate void LCD_SetData ( unsigned int cX )
{
output_bit ( LCD_D4, cX & 0x01 );
output_bit ( LCD_D5, cX & 0x02 );
output_bit ( LCD_D6, cX & 0x04 );
output_bit ( LCD_D7, cX & 0x08 );
}


Thư viện ds1307.c:


BYTE bin2bcd(BYTE binary_value);
BYTE bcd2bin(BYTE bcd_value);


void ds1307_init(void)
{
BYTE initsec = 0;
BYTE initmin=0;
BYTE inithr=0;
BYTE initdow=0;
BYTE initday=0;
BYTE initmth=0;
BYTE inityear=0;
i2c_start();
i2c_write(0xD0); // WR to RTC
i2c_write(0x00); // REG 0
i2c_start();
i2c_write(0xD1); // RD from RTC
initsec = bcd2bin(i2c_read() & 0x7f);
initmin = bcd2bin(i2c_read() & 0x7f);
inithr = bcd2bin(i2c_read() & 0x3f);
initdow = bcd2bin(i2c_read() & 0x7f); // REG 3
initday = bcd2bin(i2c_read() & 0x3f); // REG 4
initmth = bcd2bin(i2c_read() & 0x1f); // REG 5
inityear = bcd2bin(i2c_read(0)); // REG 6
i2c_stop();
delay_us(3);


i2c_start();
i2c_write(0xD0); // WR to RTC
i2c_write(0x00); // REG 0
i2c_write(bin2bcd(initsec)); // Start oscillator with current "seconds value
i2c_write(bin2bcd(initmin)); // REG 1
i2c_write(bin2bcd(inithr)); // REG 2
i2c_write(bin2bcd(initdow)); // REG 3
i2c_write(bin2bcd(initday)); // REG 4
i2c_write(bin2bcd(initmth)); // REG 5
i2c_write(bin2bcd(inityear)); // REG 6
i2c_start();
i2c_write(0xD0); // WR to RTC
i2c_write(0x07); // Control Register
i2c_write(0x90); // squarewave output pin 1Hz
i2c_stop();


}


void ds1307_set_date_time(BYTE day, BYTE mth, BYTE year, BYTE dow, BYTE hr, BYTE min, BYTE sec)
{
sec &= 0x7F;
hr &= 0x3F;


i2c_start();
i2c_write(0xD0); // I2C write address
i2c_write(0x00); // Start at REG 0 - Seconds
i2c_write(bin2bcd(sec)); // REG 0
i2c_write(bin2bcd(min)); // REG 1
i2c_write(bin2bcd(hr)); // REG 2
i2c_write(bin2bcd(dow)); // REG 3
i2c_write(bin2bcd(day)); // REG 4
i2c_write(bin2bcd(mth)); // REG 5
i2c_write(bin2bcd(year)); // REG 6
i2c_write(0x90); // REG 7 - 1Hz squarewave output pin
i2c_stop();
}


void ds1307_get_date(BYTE &day, BYTE &mth, BYTE &year, BYTE &dow)
{
i2c_start();
i2c_write(0xD0);
i2c_write(0x03); // Start at REG 3 - Day of week
i2c_start();
i2c_write(0xD1);
dow = bcd2bin(i2c_read() & 0x7f); // REG 3
day = bcd2bin(i2c_read() & 0x3f); // REG 4
mth = bcd2bin(i2c_read() & 0x1f); // REG 5
year = bcd2bin(i2c_read(0)); // REG 6
i2c_stop();
}


void ds1307_get_time(BYTE &hr, BYTE &min, BYTE &sec)
{
i2c_start();
i2c_write(0xD0);
i2c_write(0x00); // Start at REG 0 - Seconds
i2c_start();
i2c_write(0xD1);
sec = bcd2bin(i2c_read() & 0x7f);
min = bcd2bin(i2c_read() & 0x7f);
hr = bcd2bin(i2c_read(0) & 0x3f);
i2c_stop();


}


BYTE bin2bcd(BYTE binary_value)
{
BYTE temp;
BYTE retval;


temp = binary_value;
retval = 0;


while(1)
{
// Get the tens digit by doing multiple subtraction
// of 10 from the binary value.
if(temp >= 10)
{
temp -= 10;
retval += 0x10;
}
else // Get the ones digit by adding the remainder.
{
retval += temp;
break;
}
}


return(retval);
}




// Input range - 00 to 99.
BYTE bcd2bin(BYTE bcd_value)
{
BYTE temp;


temp = bcd_value;
// Shifting upper digit right by 1 is same as multiplying by 8.
temp >>= 1;
// Isolate the bits for the upper digit.
temp &= 0x78;


// Now return: (Tens * 8) + (Tens * 2) + Ones


return(temp + (temp >> 2) + (bcd_value & 0x0f));
}

Hướng dẫn lập trình cho PIC bằng CCS ver3.242

1. Tổng quan về CCS


1.1. Vì sao ta sử dụng CCS?


Sự ra đời của một loại vi điều khiển đi kèm với việc phát triển phần mềm ứng dụng cho việc lập trình cho con vi điều khiển đó. Vi điều khiển chỉ hiểu và làm việc với hai con số 0 và 1. Ban đầu để việc lập trình cho VĐK là làm việc với dãy các con số 0 và 1. Sau này khi kiến trúc của Vi điều khiển ngày càng phức tạp, số luợng thanh ghi lệnh nhiều lên, việc lập trình với dãy các số 0 và 1 không còn phù hợp nữa, đòi hỏi ra đời một ngôn ngữ mới thay thế. Và ngôn ngữ lập trình Assembly. Ở đây ta không nói nhiều đến Assmebly. Sau này khi lập trình cho Vi điều khiển một cách ngắn gọn và dễ hiểu hơn đã dẫn đến sự ra đời củangôn ngữ C ra đời, nhu cầu dùng ngôn ngữ C đề thay cho ASM trong việc mô tả các lệnh nhiều chương trình soạn thảo và biên dịch C cho Vi điều khiển : Keil C, HT‐PIC, MikroC,CCS…
Tôi chọn CCS cho bài giới thiệu này vì CCS là một công cụ lập trình C mạnh cho Vi điều khiển PIC. Những ưu và nhược điểm của CCS sẽ được đề cập đến trong các phần dưới đây.


1.2. Giới thiệu về CCS


CCS là trình biên dịch lập trình ngôn ngữ C cho Vi điều khiển PIC của hãng Microchip.
Chương trình là sự tích hợp của 3 trình biên dich riêng biết cho 3 dòng PIC khác nhau đó là:
‐ PCB cho dòng PIC 12‐bit opcodes
‐ PCM cho dòng PIC 14‐bit opcodes
‐ PCH cho dòng PIC 16 và 18‐bit
Tất cả 3 trình biên dich này đuợc tích hợp lại vào trong một chương trình bao gồm cả trình soạn thảo và biên dịch là CCS, phiên bản mới nhất là PCWH Compiler Ver 3.227.



Giống như nhiều trình biên dich C khác cho PIC, CCS giúp cho người sử dụng nắm bắt nhanh được vi điều khiển PIC và sử dụng PIC trong các dự án. Các chương trình diều khiển sẽ được thực hiện nhanh chóng và đạt hiệu quả cao thông qua việc sử dụng ngôn ngữ lạp trình cấp cao – Ngôn ngữ C.Tài liệu hướng dẫn sử dụng có rất nhiều, nhưng chi tiết nhất chính là bản Help đi kèm theo phần mềm (tài liệu Tiếng Anh). Trong bản trợ giúp nhà sản xuất đã mô tả rất nhiều về hằng, biến, chỉ thị tiền xủa lý, cấu trúc các câu lệnh trong chương trình, các hàm tạo sẵn cho người sử dụng…


2. Tạo PROJECT đầu tiên trong CCS


Để tạo một Project trong CCS có nhiều cách, có thể dùng Project Wizard, Manual Creat, hay đơn giản là tạo một Files mới và thêm vào đó các khai báo ban đầu cần thiết và “bắt buộc”.
Dưới đây sẽ trình bày cách tạo một project hợp lệ theo cả 3 phương pháp. Một điều ta cần chú ý khi tạo một Project đó là: khi tạo bắt cứ một Project nào mới thì ta nên tạo một thư mục mới với tên liên quan đến Project ta định làm, rồi lưu các files vào đó. Khi lập trình và biên dịch, CCS sẽ tạo ra rất nhiều files khác nhau, do đó nếu để chung các Project trogn một thư mục sẽ rất mất thời gian trong việc tìm kiếm sau này. Đây cũng là quy tắc chung khi ta làm việc với bất kỳ phần mềm nào, thiết kế mạch hay lập trình.
Việc đầu tiên bạn cần làm là khởi động máy tính và bật chương trình PIC C Compiler.


2.1. Tạo một PROJECT sử dụng PIC Wizard


Trước hết bạn khởi động chương trình làm việc PIC C Compiler. Từ giao diện chương trình bạn di chuột chọn Project ‐> New ‐> PIC Wizard nhấn nút trái chuột chọn.






Sau khi nhấn chuột, một cửa sổ hiện ra yêu cầu ban nhập tên Files cần tạo. Bạn tạo một
thư mục mới, vào thư mục đó và lưu tên files cần tạo tại đây.





Cửa sổ Save As


Như vậy là xong bước đầu tiên. Sau khi nhấn nút Save, một cửa sổ New Project hiện ra. Trong của sổ này bao gồm rất nhiều Tab, mỗi Tab mô tả về một vài tính năng của con PIC. Ta sẽ chọn tính năng sử dụng tại các Tab tương ứng.
Dưới đây sẽ trình bày ý nghĩa từng mục chọn trong mỗi Tab. Các mục chọn này chính là đề cập đến các tính năng của một con PIC, tùy theo từng loại mà sẽ có các Tab tương ứng. Đối với từng dự án khác nhau, khi ta cần sử dụng tính năng nào của con PIC thì ta sẽ chọn mục đó. Tổng cộng có 13 Tab đẻ ta lưa chọn. Tôi giới thiệu những Tab chính thường hay được sử dụng.


2.1.1. Tab General


Tab General cho phép ta lựa chọn loại PIC mà ta sử dụng và một số lựa chọn khác như chọn tần số thạch anh dao động, thiết lập các bit CONFIG nhằm thiết lập chế độ hoạt động cho PIC.



Tab General




‐ Device: Liệt kê danh sách các loại PIC 12F, 16F, 18F… Ta sẽ chọn tên Vi điều khiển PIC mà ta sử dụng trong dự án. Lấy ví dụ chọn PIC16F877A.
‐ Oscilator Frequency: Tần số thạch anh ta sử dụng, chọn 20 MHz (tùy từng loại)
‐ Fuses: Thiết lập các bit Config như: Chế độ dao động (HS, RC, Internal ), chế độ bảo vệ Code, Brownout detected…
‐ Chọn kiểu con trỏ RAM là 16‐bit hay 8‐bit.


2.1.2. Tab Communications


Tab Communications liệt kê các giao tiếp nối tiếp mà một con PIC hỗ trợ, thường là RS232 và I2C, cùng với các lựa chọn để thiết lập chế độ hoạt động cho từng loại giao tiếp.

Giao tiếp RS232


Mỗi một Vi điều khiển PIC hỗ trợ một cổng truyền thông RS232 chuẩn. Tab này cho phép ta lựa chọn chân Rx, Tx, tốc độ Baud, Data bit, Bit Parity…


Giao tiếp I2C


Để sử dụng I2C ta tích vào nút chọn Use I2C, khi đó ta có các lựa chọn: Chân SDA, SCL, Tốc độ truyền (Fast ‐ Slow), chế độ Master hay Slave, địa chỉ cho Salve.



Tab Communications



2.1.3. Tab SPI and LCD


Tab này liệt kê cho người dùng các lựa chọn đối với giao tiếp nối tiếp SPI, chuẩn giao tiếp tốc độ cao mà PIC hỗ trợ về phần cứng. Chú ý khi ta dùng I2C thì không thể dùng SPI và ngược lại. Để có thể sử dụng cả hai giao tiếp này cùng một lúc thì buộc một trong 2 giao tiếp phải lập trình bằng phần mềm (giồng như khi dùng I2C cho các chip AT8051, không có hỗ trợ phần cứng SSP).
Phần cấu hình cho LCD dành cho các chíp dòng 18F và 30F.



Tab SPI and LCD


2.1.4. Tab Timer


Liệt kê các bộ đếm/định thời mà các con PIC dòng Mid‐range có: Timer0, timer1, timer2, WDT…
Trong các lựa chọn cấu hình cho các bộ đếm /định thời có: chọn nguồn xung đồng hồ (trong/ngoài), khoảng thời gian xảy ra tràn…



Tab Timer



2.1.5. Tab Analog


Liệt kê các lựa chọn cho bộ chuyển đổi tương tự/số (ADC) của PIC. Tùy vào từng IC cụ thể mà có các lựa chọn khác nhau, bao gồm:
‐ Lựa chọn cổng vào tương tự
‐ Chọn chân điện áp lấy mẫu (Vref)
‐ Chọn độ phân giải: 8‐bit = 0 ~ 255 hay 10‐bit = 0~1023
‐ Nguồn xung đồng hồ cho bộ ADC (trong hay ngoài), từ đó mà ta có được tốc độ lấy mẫu, thường ta chọn là internal 2‐6 us.
‐ Khi không sử dụng bộ ADC ta chọn none



Tab Analog



2.1.6. Tab Other


Tab này cho phép ta thiết lập các thông số cho các bộ Capture/Comparator/PWM.


Capture ‐ Bắt giữ


‐ Chọn bắt giữ xung theo sườn dương (rising edge) hay sườn âm (falling edge) của xung vào
‐ Chọn bắt giữ sau 1, 4 hay 16 xung (copy giá trị của TimerX vào thanh ghi lưu trữ CCCPx sau 1, 4 hay 16 xung).


Compare ‐ So sánh


‐ Ta có các lựa chọn thực hiện lệnh khi xayư ra bằng nhau giữa 2 đối tượng so sánh là giá trị của Timer1 với giá trị lưu trong thanh ghi để so sánh. Bao gồm:
o Thực hiện ngắt và thiết lập mức 0
o Thực hiện ngắt và thiết lập mức 1
o Thực hiện ngắt nhưng không thay đổi trạng thái của chân PIC.
o Đưa Timer1 về 0 nhưng không thay đổi trạng thái chân.


PWM ‐ Điều chế độ rộng xung


‐ Lựa chọn về tần số xung ra và duty cycle. Ta có thể lựa chọn sẵn hay tự chọn tần số, tất nhiên tần số ra phải nằm trong một khoảng nhất định.


Comparator ‐ So sánh điện áp


‐ Lựa chọn mức điện áp so sánh Vref. Có rất nhiều mức điện áp để ta lựa chọn. Ngoài ra ta còn có thể lựa chọn cho đầu vào của các bộ so sánh.



Tab Other



2.1.7. Tab Interrupts và Tab Driver


Tab Interrupts cho phép ta lựa chọn nguồn ngắt mà ta muốn sử dụng. Tùy vào từng loại PIC mà số lượng nguồn ngắt khác nhau, bao gồm: ngắt ngoài 0(INT0), ngắt RS232, ngắt Timer, ngắt I2C‐SPI, ngắt onchange PORTB.v.v…
Tab Drivers được dùng để lựa chọn những ngoại vi mà trình dịch đã hỗ trợ các hàm giao tiếp. Đây là nhưng ngoại vi mà ta sẽ kết nối với PIC, trong các IC mà CCS hỗ trợ, đáng chú ý là các loại EEPROM như 2404, 2416, 2432, 9346, 9356…Ngoài ra còn có IC RAM PCF8570, IC thời gian thực DS1302, Keypad 3x4, LCD, ADC… Chi tiết ta có thể xem trong thư mục Driver của chương trình: \...\PICC\Drivers

Tab Interrupts



Tab Driver



Sau các bước chọn trên, ta nhấn OK để kết thúc quả trình tạo một Project trong CCS, một Filesten_project.c được tạo ra, chứa những khai báo cần thiết cho PIC trong một Files ten_project.h.



Sau đây là ví dụ về cấu trúc 1 chương trình trong CCS :




#include < 16F877 .h >
#device PIC6f877 *=16 ADC=10
#use delay(clock=20000000)
. . . .
Int16 a,b;
. . . .
Void xu_ly_ADC ( )
{ . . .
. . .
}


#INT_TIMER1
Void xu_ly_ngat_timer ( )
{ . . .
. . .
}


Main ( )
{ . . .
. . .
}



+ Đầu tiên là các chỉ thị tiền xử lý : # . . . có nhiệm vụ báo cho CCS cần sử dụng những gì trong chương trình C như dùng VXL gì , có dùng giao tiếp PC qua cổng COM không , có dùng ADC không , có dùng DELAY không , có biên dịch kèm các file hay không . . .
+ Các khai báo biến .
+ Các hàm con do ta viết : xu_ly_ADC () , . . .
+ Các hàm phục vụ ngắt theo sau bởi 1 chỉ thị tiền xử lý cho biết dùng ngắt nào.
+ Chương trình chính .
+ Một chương trình C có thể được viết luôn tuồn trong hàm main () , nếu chúng rất ngắn và đơn giản. Nhưng khi chương trình bắt đầu dài ra , phức tạp lên 1 chút thì phải phân chia trong các hàm con .


Các hàm này có thể là :


1/ Hàm không trả về trị.
Ví dụ :


Void xu_ly( )
{
z= x+y ;
}



Hàm trên chỉ thực hiện các lệnh trong thân hàm , khi gọi hàm này chỉ đơn giản viết :


Xu_ly( ) ;


2/ Hàm có trả về trị.
Ví dụ :


int xu_ly ( int a , int b)
{
. . . . . .
Return (a+b) ;
}

Hàm trên sẽ trả về tổng (a+b) . khi sử dụng , ví dụ tính tổng 2 biến e ,f , chương trình như sau (trong hàm main() ) :


Main()
{
Int e ,f ,g ;
e=7 ;
f= 4;
g = xu_ly(e ,f ); // giá trị g=28
}



+ Mỗi hàm con nên được viết để thực hiện 1 chức năng chuyên biệt nào đó . Bên trong 1 hàm con có thể gọi 1 hay nhiều hàm khác . Cách thức hoạt động như viết 1 chương trình C trên máy tính .
+ Nếu chương trình lớn hơn nữa có thể làm file c rất dài và do đó rất khó kiểm soát , nên sẽ cần phân chia ra các file c . trong đó file chính chứa hàm main sẽ được biên dịch . Các file c khác chứa các hàm phục vụ chuyên biệt như : cho LCD , . . .Trong file chính chỉ cần thêm dòng #include < filex.c > là tất cả hàm cần dùng chứa trong file x sẽ được biên dịch vào file hex chung. Các ví dụ trong thư mục của CCS nếu có sử dụng LCD sẽ chèn 1 dòng #include <lcd.c> và do đó sẽ gọi được các hàm trong file này mà không cần phải viết lại . điều này có nghĩa là ta có thể viết các file c chứa mã tổng quát có thể dùng chung cho nhiều project , tức là tái sử dụng mã , thay vì phải viết lại chuyên biệt cho từng project . Đây là cách làm chuyên nghiệp cho những project lớn .


Nguồn: Sưu tầm

code mẫu cho 8051 - Quét LED 7 đoạn

Chương trình quét LED 7 đoạn để hiển thị các số từ 00 đến 99.

Mã nguồn C:



#include<at89x51.h>
#define c P2_0
#define d P2_1
unsigned char so[10]={0xc0,0x79,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
void delay(int ms)
{
while(ms--)
{}
}
void hienso(unsigned char x)
{
unsigned char chuc=x/10;
unsigned char donvi=x%10;
c=1;d=1;
if(x>=10)
{
c=0;
d=1;
P0=so[chuc];
delay(50);
c=1;
d=0;
P0=so[donvi];
delay(50);

}
if(x<10)
{
c=0;
d=1;
P0=so[x];
delay(100);
}
}
main()
{
P0=0xff;
while(1)
{
unsigned char i;
for(i=0;i<100;i++)
hienso(i);
}
}





code mẫu cho 8051 - Nháy LED tạo hiệu ứng đơn giản

Chương trình mô phỏng trên ISIS - Proteus:




Mã nguồn C:

#include<at89x52.h>
unsigned char nhayled[20]={0x05,0x0e,0x1d,0x3e,0x7d,0xfe,0x01,0x82,0xc1,0xe2,0xf1,0xfa,0xfd,0x02,0xfd,0x02,0xfd,0x02,0xfd,0x02}; //cac hieu ung
void delay(unsigned int i)
{
while(i--)
{
unsigned char j=121;
while(j--){}
}
}
main()
{
unsigned char k;
while(1)
{
for(k=0;k<20;k++)
{
P0=nhayled[k];
delay(250);
}
}
}


code mẫu cho 8051 - Đo nhiệt độ, hiển thị lên LCD 16x2

Chương trình thực hiện đo nhiện độ và hiển thị kết quả lên LCD 16x2, các bước khởi tạo LCD, khởi tạo bộ ADC trong 8051.

Mã nguồn C:


#include <AT89X51.H>
#include <stdio.h>
#include<string.h>

#define RS P3_5
#define RW P3_6//RW=0 => ghi
#define EN P3_7//RW=1 => doc
//RS=0 => code
//RS=1 => data
#define LCD_PORT P1

#define INTR P3_2
#define RD P3_3
#define WR P3_4


//===========================
void delay_ms(int n)
{
int k,j;
for(k=0;k<n;k++)
{
for(j=0;j<500;j++);
}

}
//==========================
void delay_5ms()
{
int i,j;
for(i=0;i<250;i++)
for(j=0;j<4;j++){}
}
//===========================
void delay_15ms()
{
int i,j;
for(i=0;i<250;i++)
for(j=0;j<100;j++){}
}
//============================
void LCDWriteCmd(unsigned char c) //CT con ghi du lieu len LCD
{
RS=0;//code
RW=0;//ghi
LCD_PORT=c;
EN=1;
EN=0;
delay_5ms();
}
//==============================
void LCDWriteData(unsigned char c) //CT con doc du lieu tu LCD
{
RS=1;//data
RW=0;//ghi
LCD_PORT=c;
EN=1;
EN=0;
delay_5ms();
}
//===============================
void LCD_init() // Khoi tao LCD
{
delay_15ms();
LCDWriteCmd(0x38); //che do 8bit,2 hang,kieu ky tu 5x8 diem anh.
LCDWriteCmd(0x0C); //hien thi man hinh.
LCDWriteCmd(0x06); //tu dong tang bo dem dia chi
LCDWriteCmd(0x01); // Xoa man hinh LCD
}
//================================
void LCD_clear()
{
LCDWriteCmd(0x01);
}
//===============================
void LCD_home()
{
LCDWriteCmd(0x80);
}
//=============================
void LCD_putstr(unsigned char *s)
{
while (*s)
{
LCDWriteData(*s);
s++;
}
}
//============================
void HienThi_ADC(unsigned char t)
{
unsigned char v;
if(t<10)
LCDWriteData(t+48);
else if(t<100)
{
LCDWriteData(t/10+48);
LCDWriteData(t%10+48);
}
else
{
v=t/10;
LCDWriteData(v/10+48);
LCDWriteData(v%10+48);
LCDWriteData(t%10+48);
}
}
//==========================================
void main (void)
{
unsigned char gt=0; //gt la bie^n' cho gia tri 8bit ADC
LCD_init();
while(1)
{
WR=0; // Bat dau chuyen doi gia tri tu ADC
delay_ms(5); // Tao tre de cap nhat du lieu tu ADC
WR=1; //ket thuc chuyen doi.
// while(!INTR);
RD=0; // Nhan du lieu da duoc chuyen doi
gt=P2; //cap nhat ADC.
LCDWriteCmd(0x01);
LCDWriteCmd(0x83);
LCD_putstr("8051 & ADC");
LCDWriteCmd(0xC0);
LCD_putstr("Nhiet do:");
HienThi_ADC(gt);
delay_ms(150);
}
}







code mẫu cho 8051 - Đo nhiệt độ, hiển thị LCD, truyền dữ liệu qua RS232

Chương trình thực hiện kết hợp đo nhiệt độ, hiển thị lên LCD, và truyền dữ liệu lên máy tính qua giao tiếp RS232.

Mô phỏng trên ISIS - Proteus:




mô phỏng trên ISIS - Proteus
Mã nguồn C:


#include<at89x51.h>
#include<conio.h>
#include<stdio.h>
#include<string.h>
//========================= #DEFINE LCD
#define RS P3_5
#define RW P3_6//RW=0 => ghi
#define EN P3_7//RW=1 => doc
//RS=0 => code
//RS=1 => data
#define LCD_PORT P1
//========================= #DEFINE ADC
#define INTR P3_2
#define RD P3_3
#define WR P3_4
//============================================================== DELAY
void delay_ms(int n)
{
int k,j;
for(k=0;k<n;k++)
{
for(j=0;j<500;j++);
}

}
//==========================
void delay_5ms()
{
int i,j;
for(i=0;i<250;i++)
for(j=0;j<4;j++){}
}
//===========================
void delay_15ms()
{
int i,j;
for(i=0;i<250;i++)
for(j=0;j<100;j++){}
}
//============================================================== LCD
//============================== GUI LENH CHO LCD
void LCD_CODE(unsigned char c)
{
RS=0;//code
RW=0;//ghi
LCD_PORT=c;
EN=1;
EN=0;
delay_5ms();
}
//=============================== KHOI TAO LCD
void LCD_INIT()
{
delay_15ms();
LCD_CODE(0x38); //che do 8bit,2 hang,kieu ky tu 5x8 diem anh.
LCD_CODE(0x0C); //hien thi man hinh,có con tro, con tro nhâp' nháy.
LCD_CODE(0x01); // Xoa man hinh LCD
}
//============================== IN KY TU
void LCD_DATA(unsigned char c)
{
RS=1;//data
RW=0;//ghi
LCD_PORT=c;
EN=1;
EN=0;
delay_5ms();
}
//=============================== IN CHUOI KY TU
void LCD_STRING(unsigned char *s)
{
while(*s) //den NULL thi thoi
{
LCD_DATA(*s);
s++;
}
}
//============================================================== KHOI TAO RS232
void SetupSerial()
{
TMOD=0x20; /* timer 1 che do 2: 8-Bit tu dong nap lai. */
TH1=0xFD; /* toc do 9600 baud */
TL1=0xFD;
SCON=0x52; /* Che do 1: 8-bit UART, cho phep truyen */
TR1=1; /* timer 1 run */
TI=0; /* co ngat nha^n.=0*/
RI=0; /* co ngat' truye^n =0*/
ES=1; /* cho phep ngat noi tiep */
}
//============================================================== HIEN THI GIA TRI ADC LEN LCD
void HIENTHI_ADC(unsigned char t)
{
unsigned char v;
if(t<10)
LCD_DATA(t+48);
else
if(t<100)
{
LCD_DATA(t/10+48);
LCD_DATA(t%10+48);
}
else
{
v=t/10;
LCD_DATA(v/10+48);
LCD_DATA(v%10+48);
LCD_DATA(t%10+48);
}
}
//============================================================== HAM GUI SO LIEU LEN VB
void send(unsigned char a)
{
if(a<10)
{
SBUF=a+48;
while(TI==0){}
TI=0;
}
if(a>9&&a<100)
{
unsigned char c=a/10;
unsigned char d=a%10;
SBUF=c+48;
while(TI==0){}
TI=0;
SBUF=d+48;
while(TI==0){}
TI=0;
}
if(a>99)
{
unsigned char t=a/100;
unsigned char c=a/10-10*t;
unsigned char d=a%10;
SBUF=t+48;
while(TI==0){}
TI=0;
SBUF=c+48;
while(TI==0){}
TI=0;
SBUF=d+48;
while(TI==0){}
TI=0;
}
}
//============================================================== NGAT NOI TIEP
void RS232(void) interrupt 4
{
unsigned char *c,count=0;
while(RI==0){}
RI=0;
*c=SBUF;
if(count==1&&*c=='1') *c='3';
if(count==1&&*c=='2') *c='4';
switch(*c)
{
case '0': //xoa man hinh LCD
{
LCD_CODE(0x01);
}
break;
//o day co the su dung ma thap phan! (ngoai tru cac ky tu dieu khien)

case '-': //lui con tro hien thi LCD 1 don vi.
{
LCD_CODE(0x10);
}
break;

case '1': //truyen len may tinh: gia tri do duoc.
{
send(P2);
}
break;

case '2': //truyen len may tinh: gia tri do duoc.
{
send(P2);
}
break;

case '9': //thoat khoi ham ngat, cho ADC làm viec.
{
TI=0; //cho phep thoat khoi ham ngat.
count=0; //ket thuc viec truyen ky tu len LCD
}
break;

default : //truyen ky tu xuong LCD ^^.
{
if(TI==0)
LCD_CODE(0x01);
LCD_DATA(*c);
TI=1; //de cho chuong trinh ko thoat khoi ham ngat,phuc vu viec truyen ky tu len LCD.
count=1; //danh dau bat dau viec truyen ky tu len LCD
}
}
}
//============================================================== MAIN
void main()
{
SetupSerial(); //Khoi tao cac thong so cho truyen thong noi tiep
LCD_INIT();
//LCD_CODE(0x80);//hien thi 2 hang : dia chi hien thi + 80
EA = 1; //Cho phep ngat nhung chi? có ngat noi tiep duoc dung trong code nay
while(1)
{
//if(P0_3==1)
{
P0_0=P0_1=P0_2=0;
WR=0; //Bat dau chuyen doi gia tri tu ADC
delay_ms(10); //Tao tre de cap nhat du lieu tu ADC
WR=1; //Ket thuc chuyen doi
RD=0; //Chot du lieu da duoc chuyen doi: P2
LCD_CODE(0x01);
LCD_putstr("Nhiet do:");
HIENTHI_ADC(P2);
LCD_STRING(" oC");
delay_ms(300);
}
}
}

code ASM mẫu cho 8051 - Tạo xung vuông chính xác theo tỉ lệ

Chương trình ASM tạo xung vuông 70/30 tần số 12Khz, với Thạch anh 12Mhz.
Sử dụng trình dịch Reads51, mô phỏng trên Proteus:





Mã nguồn ASM:



; ------------- READS51 generated header --------------
; module : C:\Users\Sony\Desktop\xung vuong\xung.asm
; created : 02:05:56, Sunday, February 19, 2012
; -----------------------------------------------------
#include <sfr51.inc>
org 0h
main:
MOV sp,#60h

MOV TMOD,#01H ; Chon Timer0, che do 1 (16 bit)

; Chu ky xung: 1/12K=83 us
;chu ky may: 12/12M=1 us
; => 70/30 = 58/25
; 58-8=50
; 25-10=15

HERE: SETB P0.1 ;1 Bat P0.1
MOV TL0, #0CEH ;2 byte thap;CE
MOV TH0, #0FFH ;2 byte cao
SETB TR0 ;1 Khoi dong Timer0

AGAIN1: JNB TF0, AGAIN1 ;1 Kiem tra co bo dinh thoi TF0
CLR TR0 ;1 Dung bo dinh thoi
CLR TF0 ;1 Xoa co bo dinh thoi cho vong sau


CLR P0.1 ;1 Lat P0.1
MOV TL0, #0F1H ;2 byte thap;F1
MOV TH0, #0FFH ;2 byte cao
SETB TR0 ;1 Khoi dong Timer0

AGAIN2: JNB TF0, AGAIN2 ;1 Kiem tra co bo dinh thoi TF0
CLR TR0 ;1 Dung bo dinh thoi
CLR TF0 ;1 Xoa co bo dinh thoi cho vong sau

SJMP HERE ;2

end

[Code mẫu 8051] Hiển thị trên matrix 8x8


Code cho các bác tham khảo nhé, mún chỉnh nhanh chậm thì sửa 2 dòng delay hoặc delay vòng lập, muốn thêm port để đk 8x16 hay 8x24 thì gọi thêm thôi, chúc các bác thành công:

#include <REGX51.H>
/* Cot tu P1.0 den 1.7
Hang tu P2.0 den P3.7
De quet dua muc logic 0 lan luot ra cong 0
*/
/* Ham tre */
void delay(long time)
{
long n;
for(n=0; n<time; n++)
{
;
}
}
unsigned char kytu1[9];
unsigned char k=0;
/* Ham nap gia tri hien thi cac ky tu vao mang kytu1
co 8 gia tri dua ra va 1 gia tri khong bat den nao de cac ky tu cach nhau 1 cot */
void mahoa(unsigned char x)
{
switch(x)
{
case 0: { kytu1[0]=0x00; kytu1[1]=0x00; kytu1[2]=0x00; kytu1[3]=0x00;
kytu1[4]=0x00; kytu1[5]=0x00; kytu1[6]=0x00; kytu1[7]=0x00; kytu1[8]=0x00;
break; }
case 1: { kytu1[0]=0x00; kytu1[1]=0x3E; kytu1[2]=0x0A; kytu1[3]=0x0E;
kytu1[4]=0x00; kytu1[5]=0x38; kytu1[6]=0x08; kytu1[7]=0x08; kytu1[8]=0x00;
break; }
case 2: { kytu1[0]=0x00; kytu1[1]=0x38; kytu1[2]=0x28; kytu1[3]=0x38;
kytu1[4]=0x00; kytu1[5]=0x38; kytu1[6]=0xA8; kytu1[7]=0xF8; kytu1[8]=0x00;
break; }
case 3: { kytu1[0]=0x00; kytu1[1]=0x38; kytu1[2]=0x08; kytu1[3]=0x08;
kytu1[4]=0x00; kytu1[5]=0x38; kytu1[6]=0x28; kytu1[7]=0x38; kytu1[8]=0x20;
break; }
case 4: { kytu1[0]=0x20; kytu1[1]=0x00; kytu1[2]=0x38; kytu1[3]=0x08;
kytu1[4]=0x38; kytu1[5]=0x08; kytu1[6]=0x38; kytu1[7]=0x00; kytu1[8]=0x38;
break; }
case 5: { kytu1[0]=0x38; kytu1[1]=0x08; kytu1[2]=0x38; kytu1[3]=0x08;
kytu1[4]=0x38; kytu1[5]=0x00; kytu1[6]=0x38; kytu1[7]=0x00; kytu1[8]=0x38;
break; }
case 6: { kytu1[0]=0x38; kytu1[1]=0x08; kytu1[2]=0x38; kytu1[3]=0x00;
kytu1[4]=0x38; kytu1[5]=0xA8; kytu1[6]=0xF8; kytu1[7]=0x00; kytu1[8]=0x00;
break; }
case 7: { kytu1[0]=0x00; kytu1[1]=0x3C; kytu1[2]=0x0A; kytu1[3]=0x3C;
kytu1[4]=0x02; kytu1[5]=0x3E; kytu1[6]=0x02; kytu1[7]=0x00; kytu1[8]=0x3E;
break; }
case 8: { kytu1[0]=0x3E; kytu1[1]=0x2A; kytu1[2]=0x3E; kytu1[3]=0x00;
kytu1[4]=0x2E; kytu1[5]=0x2A; kytu1[6]=0x3E; kytu1[7]=0x00; kytu1[8]=0x3E;
break; }
case 9: { kytu1[0]=0x3E; kytu1[1]=0x22; kytu1[2]=0x22; kytu1[3]=0x00;
kytu1[4]=0x28; kytu1[5]=0x10; kytu1[6]=0x28; kytu1[7]=0x00; kytu1[8]=0x28;
break; }
case 10: { kytu1[0]=0x28; kytu1[1]=0x10; kytu1[2]=0x28; kytu1[3]=0x00;
kytu1[4]=0x00; kytu1[5]=0x00; kytu1[6]=0x00; kytu1[7]=0x00; kytu1[8]=0x00;
break; }
case 11: { kytu1[0]=0x00; kytu1[1]=0x00; kytu1[2]=0x00; kytu1[3]=0x00;
kytu1[4]=0x00; kytu1[5]=0x00; kytu1[6]=0x00; kytu1[7]=0x00; kytu1[8]=0x00;
break; }
case 12: { kytu1[0]=0x00; kytu1[1]=0x00; kytu1[2]=0x00; kytu1[3]=0x00;
kytu1[4]=0x00; kytu1[5]=0x00; kytu1[6]=0x00; kytu1[7]=0x00; kytu1[8]=0x00;
break; }
}
}
/* Ham quet led ma tran_ vua hien thi vua dich ky tu dan sang trai*/
void hienthi(void)
{
unsigned char n,m,lap;
unsigned char cot[8]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};
for(m=0; m<8 ; m++)
{
for(lap=0; lap<10; lap ++)
{
for(n=0; n<8 ; n++)
{
if((n+m)<9 )
{
mahoa(k);
P0=cot[n];
P2=kytu1[n+m];
delay(45);
}
if((n+m) > 7)
{
mahoa(k+1);
P0=cot[n];
P2=kytu1[n+m-8];
delay(45);
}
P0=0xFF;
P2=0x00;
}
}
}
}
void main(void)
{
while(1)
{
hienthi();
k=k+1;
if(k==12) k=0;
}
}




Thứ Sáu, 19 tháng 10, 2012

[Lập trình ARM-LPC2378] Cách Chuyển Đổi Tương Tự/ Số - ADC, DAC

Nội dung

+ Tạo file Thư viện *.lib
+ Chuyển đổi Tương tự - Số: ADC
+ Chuyển đổi Số - Tương tự: DAC

Tạo file thư viện*.lib







+ Có 1 project định nghĩa các hàm.
+ Biên dịch project này ra file *.lib.
+ Một project khác add file .lib này vào và có thể gọi sử dụng các hàm trong file *.lib.
+ File gọi *.lib là file thư viện.


ADC
Giới thiệu
+ LPC2378 hỗ trợ 8 kênh chuyển đổi ADC


Các thanh ghi liên quan
+ AD0CR ( A/D Control Register ): Thanh ghi điều khiển AD - chọn chế độ xử lý cho qua trình chuyển đổi AD.
+ AD0GDR ( A/D Global Data Register ): Thanh ghi dữ liệu toàn cục - Chứa kết quả chuyển đổi AD gần nhất.
+ AD0STAT ( A/D Status Register ): Thanh ghi trạng thái - Cờ DONE và OVERRUN cho tất cả các kênh.
+ AD0INTEN (A/D Interrupt Enable Register): Thanh ghi bật / ngắt.

+ AD0DRn (A/D Channel n Data Register): Thanh ghi chứa dữ liệu tại kênh n– chứa kết quả chuyển đổi gần nhất trên kênh n.


Bật Power
Quản lý bởi Thanh ghi PCONP tại địa chỉ 0xE01FC0C4:






Cấu hình PINSEL





Đọc giá trị ADC

+ Kết quả chuyển đổi AD dược đọc tại thanh ghi AD0DR0 (từ bit thứ 6 đến bit thứ 15):
value = (AD0DR0 >> 6) & 0x3FF;





DACGiới thiệu
Bộ DAC chuyển đổi dữ liệu số thành tín hiệu bên ngoài (điển hình là âm thanh)


Các thanh ghi liên quan

+ DACR (D/A Control Register) : thanh ghi điều khiển AD –để đặt giá trị cần thay đổi tới.


Cấu hình PINSEL






PINSEL1 &= ~(0x03<<20); //enable DAC
PINSEL1 &= ~(0x02<<20); //enable DAC
(nguồn: ĐHKHTN TP.HCM)

[Lập trình ARM-LPC2378] Các Ngắt Trong LPC23xx

Nội Dung

+ Giới thiệu về ngắt trong LPC23xx
+ Các thanh ghi liên quan tới điều khiển ngắt
+ Hàm cài đặt ngắt install_irq()


Giới thiệu về ngắt trong LPC23xx

+ LPC2378 hỗ trợ 32 ngắt với 16 mức độ ưu tiên.
+ Có 2 loại ngắt: Interrupt request (IRQ) và Fast Interrupt Request (FIQ).
+ Fast Interrupt Request là ngắt có độ ưu tiên cao nhất. IRQ có độ ưu tiên thấp hơn.
+ Nếu có nhiều ngắt cùng độ ưu tiên thì ngắt nào ở Vector có chỉ số nhỏ hơn sẽ được thực thi trước.





+ Bảng trên thể hiện vị trí thứ tự các bit tương ứng với ngắt cho từng loại đối tượng.




Các thanh ghi liên quan tới điều khiển ngắt

+ VICIRQStatus (32bits) : Thanh ghi trạng thái của ngắt loại IRQ, bit bật lên 1 cho biết đối tượng ngắt tương ứng được kích hoạt và loại ngắt là IRQ.
+ VICFIQStatus (32bits) : Thanh ghi trạng thái của ngắt loại FIQ, bit bật lên 1 cho biết đối tượng ngắt tương ứng được kích hoạt và loại ngắt là FIQ.
+ VICVectAddrn (32bits) : Thanh ghi địa chỉ, chỉ tới hàm sẽ thực hiện nếu có ngắt xảy ra.
+ VICIntEnable (32bits) : Cho giá trị bằng 1 ở bit muốn cài đặt.
+ VICVectPriorityn (32bits) : Thanh ghi xét độ ưu tiên.
n: bit thứ n ( Với n: 0 -> 31 ).
Ví Dụ:
VICVectAddr4 = ( unsigned long ) TO_IRQHandler;
VICVectCnt4 = 15;
VICIntEnable = ( 1 << 4 );


+ Với n=4: Ngắt của Timer0
+ Hàm thực hiện khi ngắt xảy ra là TO_IRQHandler
+ Độ ưu tiên cho ngắt là 15
+ Khởi động Bộ điều khiển ngắt ở bit thứ 4


Khai báo
+ Hàm ngắt: có từ khóa __irq hoặc __fiq
VD:
void TO_IRQHandler(void)__irq
{
...
VICVectAddr = 0;
}
__irq void TO_IRQHandler(void)
{
...
VICVectAddr = 0;
}




Hàm cài đặt ngắt install_irq()
Hàm cài đặt ngắt
DWORD install_irq( DWORD IntNumber, void *HandlerAddr, DWORD Priority )
{
DWORD *vect_addr;
DWORD *vect_prio;


VICIntEnClr = 1 << IntNumber; //Disable Interrupt
if( IntNumber >= VIC_SIZE )
{
return( FALSE );
}
else
{
/* find first un assigned VIC address for the handler */
vect_addr = (DWORD *)(VIC_BASE_ADDR + VECT_ADDR_INDEX + IntNumber*4);
vect_prio = (DWORD *)(VIC_BASE_ADDR + VECT_PRIO_INDEX + IntNumber*4);
*vect_addr = (DWORD)HandlerAddr; /* set interrupt vector */
*vect_prio = Priority;
VICIntEnable = 1 << IntNumber; /* Enable Interrupt */
return( TRUE );
}
}




Ví Dụ: Tạo ngắt cho Interrupt0 Button(INT0)





+ PINSEL4 = 0x01 << 20;
+ VICVectAddr14 = (unsigned long)abc;
+ VICVectCntl14 = 14;
+ VICIntEnable = (1 << 14);
+ __irq void abc (void)
{
……// xuat ten cua ban ra HyperTerminal
EXTINT=0x01;
VICVectAddr = 0;
}


(nguồn: ĐHKHTN TP.HCM)

[Lập trình ARM-LPC2378] Truyền Thông Nối Tiếp Không Đồng Bộ- UART

Nội dung
- - Giới thiệu về UART
- Các thanh ghi liên quan tới UART
- Cấu hình PINSEL
- Sử dụng Hyper Terminal


Giới thiệu về UART
Cổng COM









UART
+ + Viết tắt của: Universal Asynchronous Receiver/ Transmitter - Bộ thu/ phát không đồng bộ đa năng, là một loại thu/ phát không đồng bộ dùng để thực hiện việc chuyển đổi dữ liệu song song thành dữ liệu nối tiếp và truyền nhận nối tiếp giữa các bên phát và thu.
- + LPC2378 hỗ trợ 4 UARTs: UART 0, UART 1, UART 2, UART 3
- + UART 0/2/3: TXD, RXD
- + UART 1: TXD, RXD, CTS, RTS, DTR, DSR, RI…
-


Các thanh ghi liên quan tới UART
Các thanh ghi
- + UnRBR ( Receive Buffer Register, 1 byte) : thanh ghi chứa byte dữ liệu nhận.
- + UnTHR ( Transmit Holding Register, 1 byte): Thanh ghi chứa byte dữ liệu sẽ được gửi.
- + UnLCD (Line Control Register, 1 byte): Thanh ghi điều khiển, quyết định định dạng dữ liệu được truyền nhận (DataLength, Stop bit, Parity…)
- + UnIER (Interrupt Identification Register, 4 bytes ): thanh ghi để active 3 ngắt sử dụng cho UART
- + UnllR ( Interrupt Identification Register, 4 bytes) : thanh ghi cho biết có ngắt đang xảy ra hay không, nếu có thì là ngắt nào
- + UnDLL ( Divisor Latch LSB Register, 1 byte): quyết định baudrate của UART
- + UnDLM (Divisor Latch MSB Register, 1 byte)


Thanh ghi UnLSR
- + Nhận dữ liệu:
- Ta xét trạng thái ở bit 0
0: Thanh ghi UnRBR rỗng
1: Thanh ghi UnRBR có chứa dữ liệu
Int getkey (void)
{
While (!(UxLSR & 0x01));
Return (UxRBR);
}
- + Truyền dữ liệu:
+ Ta xét trạng thái ở bit 5
0: Thanh ghi UnTHR có chứa dữ liệu
1: Thanh ghi UnTHR rỗng
Int sendchar (int ch)
{
While (!(UxLSR & 0x20));
Return (UxTHR = ch);
}




Cấu hình PINSEL


Cấu hình PINSEL – UARTO





Cấu hình PINSEL – UART1










Sử dụng Hyper Terminal


Hyper Terminal
Các bạn Download phần mềm Hyper Terminal hercules 3.2.4 Tại Đây!


Các thông tin truyền nhận qua cổng COM
+ Baudrate: 9600 bps ( bits per second )
+ Data length: 8 bits
+ Parity: None
+ Stop bit: 1
+ Flow control: None


Thiết lập các thông số cho UART
+ Khi sử dụng thanh ghi UxDLL và UxDLM thì bit DLAB trong thanh ghi UxLCR phải là 1.
UxLCR = 0x83; // 8 bits, no Parity, 1 Stop bit
UxDLL = 78; // 9600 Baud Rate @ 12.0 MHZ PCLK
UxDLM = 0; // High divisor latch = 0
UxLCR = 0x03; // DLAB = 0
+ Sau khi thiết lập xong cho bit DLAB = 0 để sử dụng thanh ghi UnRBR, UnTHR

(Nguồn: ĐHKHTN TP.HCM)

Hướng Dẫn Lập Trình ARM - LPC2378

Nội Dung
+ Giới thiệu về thành phần Board LPC2378.
+ Cài đặt và cấu hình Chương trình Keil uVision3.
+ Cách flash chương trình xuống Board qua JTAG và bằng công cụ Flash Magic.


Giới thiệu Chip LPC2378
+ LPC2378 của NXP là MCU thuộc họ ARM7 - TDMI
+ Tốc độ CPU: 72MHz
+ Rom: 512Kbytes
+ Bộ nhớ: 58Kbytes
- RAM: 32kb
- USB RAM: 8k
- Ethernet RAM: 16k
- RTC RAM: 2k
+ Nguồn: 3.3V





Thiết bị ngoại vi





Chương trình KEIL









Kết nối board với máy tính thông qua ULINK2
+ Bước 1: Kết nối U-LINK với PC thông qua cable USB.
+ Bước 2: Kết nối U-LINK đến cổng JTAG nằm trên board LPC.
+ Bước 3: Cấp nguồn cho board MCB2300 bằng cable USB.







Cấu hình trong chương trình Keil uVision
+ Dùng công cụ phát triển Keil uVision để tạo, biên dịch, download, debug và chạy chương trình trên board MCB2300.
+ Trong Phần menu Flash/Configủa Flash Tool, chọn Tab Debug, ta nhận thấy thông số của thiết bị JTAG và nên chọn Max JTAG, Clock là 200kHz.





+ Và trong Tab Utilities như sau:







Config vùng nhớ ROM
+ Cấu hình vùng nhớ ROM tại IROM1 với vị trí bắt đầu Start có giá trị 0x0 và kích thước Size có giá trị 0x80000.







Config vùng nhớ RAM
+ Cấu hình vùng nhớ RAM tại IRAM1 với vị trí bắt đầu Start có giá trị 0x40000000 và kích thước Size có giá trị 0x8000.





Biên dịch chương trình











Download xuống board









Kết nối thông qua giao tiếp Serial
+ Tiện ích Flash Magic: Kết nối cổng COM của PC với cổng Serial (UART) của board MCB2300 để nạp chương trình qua board với giao diện ISP Flash.
+ Đánh dấu Create HEX File để tạo file Hex cho những tiện ích Flash bên ngoài.









Cấu hình để chạy Flash Magic
+ Thiết lập jumer trên board MCB2300:
- j9 và j10: ON.
- j13: OFF.
+ Chạy "Flash Magic" và thiết lập thông số như sau:









Flash xuống board
+ Thực hiện theo từng bước trong Flash Magic và flash file .Hex xuống board.






(Nguồn: ĐHKHTN TP.HCM)

[Lập trình ARM-LPC2378] Tổ Chức Bộ Nhớ, Thiết Lập Pin, GPIO, Debug


Nội Dung
+ Cách tổ chức bộ nhớ trong LPC2378
+ Cách thiết lập PIN
+ Debug chương trình


Cách tổ chức bộ nhớ trong LPC2378
+ Bộ xử lý ARM có thể quản lý một không gian địa chỉ bộ nhớ 4Gb
+ Bảng sau đây thể hiện sự phân bố địa chỉ của vùng bộ nhớ trong các thiết bị ARM:







Địa chỉ vùng nhớ LPC23xx


Cách thiết lập PIN
Cấu hình PIN - LPC2378
+ Chip LPC2378 có 144 chân. Với sơ đồ chân như sau:





+ Mỗi chân tương ứng có những chức năng, nhiệm vụ khác nhau.
Ví Dụ:





Thanh ghi PINSEL
+ Các thanh ghi PINSEL (PINSEL0 - PINSEL10) đảm nhiệm việc kết nối giữa các PIN và các thiết bị ngoại vi.
+ Các thanh ghi cấu hình này điều khiển thiết lập những chức năng khác nhau, với mỗi 2Bit tương ứng ta có 4 trường hợp như sau:





Ví Dụ:





Địa chỉ thanh ghi PINSEL
+ Mỗi thanh ghi PINSEL có 4Bytes









GPIO
+ Viết tắt của: General Purpose Input Output.
+ Là chân input/output.
+ LPC2378 có 104 chân có chức năng GPIO.
+ Được thiết lập qua 5 Port 32Bit:





+ Việc điều khiển trực tiếp trong thanh ghi GPIO chỉ có hiệu quả khi chức năng GPIO được chọn tại các PICSEL.
Ví Dụ:



+ Muốn chọn Port0.0 và 0.1 là GPIO thì PINSEL0=0x00; (giá trị mặc định của PINSEL).
+ Low GPIO được điều khiển bởi các thanh ghi: IOPIN, IOSET, IODIR, IOCLR. (Chỉ cho Port0 và Port1)
+ Fast GPIO được điều khiển bởi các thanh ghi: FIOPIN, FIOSET, FIODIR, FIOCLR, FIOMASK.








Ví Dụ:
+ Cấu hình Port0.6 là output:
- IODIR0 = 0x00000040; //Bit thứ 6 được bật lên 1: [ 0000 0000 0100 0000 ]
+ Cấu hình Port0.6 ở mức tín hiệu cao:
- IOSET0 = 0x00000040;
+ Cấu hình Port0.6 ở mức tín hiệu thấp:
- IOCLR0 = 0x00000040;


Ví Dụ - Lập trình LED trên Board MCB2300
+ Các đèn LED trên Board được thể hiện qua Port2.0 đến port2.7:
Void LED_Init(void)
{
PINSEL10 = 0;
FIO2DIR = 0x000000FF; //P2.0 - P2.7 là Output.
FIO2MASK = 0x00000000;
}
+ Tắt / mở LES:
Void LED_On(unsigned int num)
{
FIO2SET = (1<<num); //VD: n=2 => FIO2SET = (1<<2) <=> FIO2SET = 0x04;
}
Void LED_Off(unsigned int num)
{
FIO2CLR = (1<<num);
}




Debug chương trình
Debug



DBS M05479
Quang Cao