10.4. Sử dụng capture_LCD
#include <16F877A.h>
#include
#use delay(clock=20000000)
#FUSES NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9)
#bit TMR1IF = 0x0C.0
#include
int16 CCP1Value; // Gia tri CCP hien tai
int16 CCP1OldValue; // Gia tri CCP truoc do
BOOLEAN CCP1Captured;
float Freq;
int8 char1,char2,char3,char4,char5,char6;
#int_CCP1
CCP1_isr()
{
if(TMR1IF)
{
CCP1Value = CCP_1 +(65535-CCP1OldValue);
CCP1OldValue = CCP_1;
TMR1IF=0;
}
else
{
CCP1Value = CCP_1 - CCP1OldValue;
CCP1OldValue = CCP_1;
}
CCP1Captured = TRUE;
}
//--------------------------------------------------------------------------
#INT_TIMER1
Timer1_isr()
{
IF (RB0==1) RB0=0;
Else RB0=1;
}
//----------------------------------------
void Init_ccp(void)
{
setup_ccp1(CCP_CAPTURE_RE);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
CCP1Value = 0;
CCP1OldValue = 0;
CCP1Captured = TRUE;
enable_interrupts(INT_CCP1);
//enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
}
//--------------------------------------------------------------------------
void Convert_CCP1()
{
long temp;
int8 temp2;
Freq = 1.0/((float)CCP1Value*1.6e-6);
temp = (long)freq;
char1 = ((temp / 100) + 0x30);
temp2 = (temp % 100);
char2 = ((temp2 / 10) + 0x30);
char3 = ((temp2 % 10) + 0x30);
}
//---------------------------------------------------------------
void main()
{
TRISB = 0;
Init_ccp();
LCD_init();
printf("Frequence test:\r\n");
while (TRUE) {
if (CCP1Captured) {
// F = 1/T
// Timer1 prescaler DIV_BY_8
// Pic16F877A 4MHz -> 0.000001 * 8 = 1uS * 8
// PIC16f877a 20MHz -> 0.0000002 * 8
Convert_CCP1();
LCD_putcmd(0x80);
Printf(LCD_putchar,"Freq = ");
LCD_putchar(char1);
LCD_putchar(char2);
LCD_putchar(char3);
Printf(LCD_putchar," Hz");
printf("Freq:%f\r\n",Freq);
CCP1Captured = FALSE;
}
}
}
10.5. Sử dụng capture
#include <16F877A.h>
#use delay(clock=4000000)
#fuses HS,NOWDT, NOPROTECT
//#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9,errors)
int16 CCP1Value;
int16 CCP1OldValue;
BOOLEAN CCP1Captured;
#int_CCP1 // Ngat do CCCP1 xay ra, thuc hien lenh...
CCP1_isr()
{
CCP1Value = CCP_1 - CCP1OldValue;
CCP1OldValue = CCP_1;
CCP1Captured = TRUE;
}
//--------------------------------------------------------------------------
void Init_ccp(void) //Khoi tao chuc nang CCCP
{
setup_ccp1(CCP_CAPTURE_RE);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
CCP1Value = 0;
CCP1OldValue = 0;
CCP1Captured = TRUE;
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);
}
//--------------------------------------------------------------------------
void main()
{
float Freq;
Init_ccp();
printf("Frequence test:\r\n");
while (TRUE) {
if (CCP1Captured) {
// F = 1/T
// Timer1 prescaler DIV_BY_8
// Pic16F876 4Mz -> 0.000001 * 8
Freq = 1.0/((float)CCP1Value*8e-6);
printf("Freq:%f\r\n",Freq);
CCP1Captured = FALSE;
}
}
}
11. SPI
// SPI MICROWIRE INTERFACE HANDLER
// COPYRIGHT PROPERTY OF ALPHADATA DESIGNS LIMITED (c) 1999
// published by permission of Alphadata designs on
// Hi-Tech C website, http://www.workingtex.com/htpic. Thanks!
// P4/0 : OUTPUT : DATA OUT
// P4/1 : OUTPUT : CLOCK
// P4/2 : OUTPUT : CHIP SELECT ATOD
// P4/3 : OUTPUT : CHIP SELECT DTOA
// P4/7 : INPUT : DATA IN
//
//------------------------------------------------------
// Version History
//------------------------------------------------------
// Issue 1.0 : 21/12/1999 : First Officially Released
//------------------------------------------------------
#include "h8genlib.h"
#include "ioh8314.h"
extern byte p4dr;
// Select device
void spi_dac_select(void)
{
p4dr = p4dr & 0b11110111;
P4DR = p4dr;
}
// Deselect device
void spi_dac_deselect(void)
{
p4dr = p4dr | 0b00001000;
P4DR = p4dr;
}
// Select device
void spi_adc_select(void)
{
p4dr = p4dr & 0b11111011;
P4DR = p4dr;
}
// Deselect device
void spi_adc_deselect(void)
{
p4dr = p4dr | 0b00000100;
P4DR = p4dr;
}
// Set clock high
void spi_hiclock(void)
{
p4dr = p4dr | 0b00000010;
P4DR = p4dr;
}
// Set clock low
void spi_loclock(void)
{
p4dr = p4dr & 0b11111101;
P4DR = p4dr;
}
// Set Data high
void spi_hidata(void)
{
p4dr = p4dr | 0b00000001;
P4DR = p4dr;
}
// Set data low
void spi_lodata(void)
{
p4dr = p4dr & 0b11111110;
P4DR = p4dr;
}
// end
12. Các chuẩn giao tiếp
12.1. Chuẩn giao tiếp I2C
-Sơ đồ:
-Mình dùng lệnh I2C trong CCS có hiệu quả ko ?!
Vì mình đang viết thử I2C. Thấy chương trình mẫu(EX_Slave) trong CCS C mô phỏng bộ nhớ ngoài 24xx chuẩn, nên nạp chạy thử thấy: viết từ Master (Ctr Mater lấy ví dụ: EX_EXTEE) ít nhất là 4 lần mới được, còn đọc thì lại ko được. Xem tài liệu thì thấy có rất nhiều bit bẫy tình huống I2C, nhưng các lệnh về I2C trong CCS thì đơn giản và ít. Vậy, có vấn đề gì không.
Code:
#include <16F876A.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0xa0)
typedef enum {NOTHING, CONTROL_READ,
ADDRESS_READ, READ_COMMAND_READ} I2C_STATE;
I2C_STATE fState;
BYTE address, buffer[0x10];
#INT_SSP
void ssp_interupt ()
{
BYTE incoming;
if (i2c_poll() == FALSE) {
if (fState == ADDRESS_READ) { //i2c_poll() returns false on the
i2c_write (buffer[address]);//interupt receiving the second
fState = NOTHING; //command byte for random read operation
}
}
else {
incoming = i2c_read();
if (fState == NOTHING){
fState = CONTROL_READ;
}
else if (fState == CONTROL_READ) {
address = incoming;
fState = ADDRESS_READ;
}
else if (fState == ADDRESS_READ) {
buffer[address] = incoming;
fState = NOTHING;
}
}
}
void main ()
{
int i;
fState = NOTHING;
address = 0x00;
for (i=0;i<0x10;i++)
buffer[i] = 0x00;
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
while (TRUE) {}
}
Hà vừa thử chtr I2c: Master 16F877A, Slave 16F876A, cùng giao tiếp PC để kiểm tra dữ liệu đọc và viết của Master và Slave> Thấy rất tốt ! I2C hay thiệt! Nhiêm vụ bây giờ mình chỉ tạo giao thức dữ liệu, còn chtr service plug&play slave thì thấy hơi khó! Nhưng mònh cố gắn viết thử. Cảm ơn Hoanf, mọi người rất nhiều !!
Code:
**********************************************
Chtr Master, mình thay đổi chút ít từ chtr mẫu EX_EXTEE.
1.chỉ liên kết 2401.c (thay vì địa chỉ mặc đinh là 0xa0,
mình thay là 0x10).
2. Vẫn truyền lệnh từ PC
**********************************************
#include <16F877A.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#include
#include <2401.c>
void main() {
BYTE value, cmd;
EEPROM_ADDRESS address;
init_ext_eeprom();
do {
do {
printf("\r\nRead or Write: ");
cmd=getc();
cmd=toupper(cmd);
putc(cmd);
} while ( (cmd!='R') && (cmd!='W') );
printf("\n\rLocation: ");
address = gethex1();
if(cmd=='R')
printf("\r\nValue: %X\r\n",READ_EXT_EEPROM( address ) );
if(cmd=='W') {
printf("\r\nNew value: ");
value = gethex();
printf("\n\r");
WRITE_EXT_EEPROM( address, value );
}
} while (TRUE);
}
Code:
**********************************************
Chtr Slave, thì có thay đổi chút ít từ chtr mẫu EX_Slave:
1. giám sát 3 ô nhớ trên PC
2. khai báo địa chỉ la 0x10.
**********************************************
#include <16F876A.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0x10)
BYTE address, buffer[0x10];
#INT_SSP
void ssp_interupt ()
{
BYTE incoming, state;
state = i2c_isr_state();
if(state < 0x80) //Master is sending data
{
incoming = i2c_read();
if(state == 1) //First received byte is address
address = incoming;
if(state == 2) //Second received byte is data
buffer[address] = incoming;
}
if(state == 0x80) //Master is requesting data
{
i2c_write(buffer[address]);
}
}
void main ()
{
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
while (TRUE) {
printf("\r\nValue0: %X\r\n",buffer[0]);
delay_ms(1000);
printf("\r\nValue1: %X\r\n",buffer[1]);
delay_ms(1000);
printf("\r\nValue2: %X\r\n",buffer[2]);
delay_ms(1000);
printf("\r\nValue3: %X\r\n",buffer[3]);
delay_ms(1000);
}
}
Mình mới viết được chương trình giao tiếp I2C đơn giản dùng các hàm của CCS.
Mời các bạn xem và cho nhận xét
Master: truyền dữ liệu cho Slave. Mỗi lần truyền 1 byte.
Code:
#include <16F877A.H>
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use Delay(Clock=4000000)
#define SLAVE_ADDRESS 0x10
#use i2c(master, sda=PIN_C4, scl=PIN_C3)
void write_I2C(int8 a)
{
i2c_start();
i2c_write(SLAVE_ADDRESS);
i2c_write(a);
i2c_stop();
}
void main()
{
int8 value;
value = 0;
while(1){
write_I2C(value);
value++;
delay_ms(100);
}
}
Slave thì chỉ tiến hành kiểm tra có phải Master truyền hay kô. Nếu truyền thì nhận byte dữ liệu và hiển thị lên port_B:
Code:
#include <16F877A.H>
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay(Clock=4000000)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0x10)
int8 value;
#INT_SSP
void i2c_isr()
{
int8 state;
int8 address;
state = i2c_isr_state();
if(state == 0)
address = i2c_read();
else if(state < 0x80)
value = i2c_read();
}
void main()
{
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
set_tris_b(0x00);
while(1){
output_b(value);
}
}
Mình gặp trục trặc khi đọc dữ liệu từ Slave về.
Đây là đoạn code sử dụng cho 2 con PIC 18F877A.
Master: Yêu cầu Slave nhận dữ liệu liên tục (cách nhau 500ms) và nó sẽ hiển thị giá trị nhận được lên Port_b. Dùng leds để quan sát.
Code:
#include <16F877A.H>
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use Delay(Clock=4000000)
#define SLAVE_ADDRESS 0x10
#use i2c(master, sda=PIN_C4, scl=PIN_C3)
int8 read_I2C()
{
int8 value;
i2c_start();
i2c_write(SLAVE_ADDRESS + 1);
value = i2c_read();
i2c_stop();
return value;
}
void main()
{
int8 value;
set_tris_b(0x00);
while(1){
value = read_I2C();
output_b(value);
delay_ms(500);
}
}
Slave: Truyền dữ liệu cho master và mỗi lần truyền thì giá trị cần truyền tăng lên 1 đơn vị.
Code:
#include <16F877A.H>
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay(Clock=4000000)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0x10)
int8 value = 0x01;
#INT_SSP
void i2c_isr()
{
int8 state;
int8 address;
state = i2c_isr_state();
if(state >= 0x80){
i2c_write(value);
value++;
}
}
void main()
{
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
set_tris_b(0x00);
while(1){
output_b(value);
}
}
Theo Hà nghĩ, ở Master, khi mình đọc cũng phải chờ xung ACK từ Slave thì chtr ko bị rối.
Bạn thử thêm một chtr con chờ Bus trong <2401.c>:
Code:
//**************code thêm vào*********************
BOOLEAN ext_eeprom_ready()
{
int1 ack;
i2c_start();
ack = i2c_write(SLAVE_ADDRESS);
i2c_stop();
return !ack;
}
//**********************************************
int8 read_I2C()
{
int8 value;
while(!ext_eeprom_ready()); // code thêm vào
i2c_start();
i2c_write(SLAVE_ADDRESS + 1);
value = i2c_read();
i2c_stop();
return (value);
}
void main()
{
int8 value;
value = 0x00;
set_tris_b(0x00);
while(1){
value = read_I2C();
output_b(value);
delay_ms(500);
}
}
12.1.1. Master_Slave
12.1.1.1. I2Cmaster
//**************************************************************************
// Day la chuong trinh vi du su dung truyen thong I2C
// This program is a sample of I2C comunication.
//This is master mode
//This include next funtions:
// 1. Send ASCII code periodically to slave
// 2. Display send data on LCD display
// Hanoi: 12/5/2007
//Writer: Nguyen Khac Hieu
//user: all of my friends and students etc...
//**************************************************************************
#include <16F84A.h>
#fuses NOWDT,PUT,HS,NOPROTECT
#use delay(clock=4000000)
#byte PORTA=5
#byte PORTB=6
// Khai bao LCD
#define rs PIN_A2
#define rw PIN_A1
#define stb PIN_A0
#byte db = 6 // khai bao c?ng D cho LCD
#define Amode 0x0
#define Bmode 0x0F
#include
#use I2C(master, sda=PIN_A4, scl=PIN_A3)
// Chuong trinh chinh
void khoitao();
void main(void)
{
int asci,i;
set_tris_b(Bmode);
set_tris_a(Amode);
lcd_init();
lcd_clear();
lcd_data("Start I2C test");
delay_ms(3000);
while(1)
{
asci=0x30;
lcd_clear();
do{
i2c_start();
i2c_write(0xa0);
for(i=1;i<=8;++i){
i2c_write(asci);
lcd_data(asci);
asci=asci+1;
delay_us(100);
}
i2c_stop();
delay_ms(1000);
}while(asci<0xFE);
}
}
12.1.1.2. I2Cslave
//**************************************************************************
// This program is a sample of I2C comunication.
//This is slave mode
//This include next funtions:
// 1. Receive data from I2C master CPU
// 2. Display received data on LCD display
// Hanoi: 12/5/2007
//Writer: Nguyen Khac Hieu
//user: all of my friends, my students etc...
//**************************************************************************
#include <16F877A.h>
#fuses NOWDT,PUT,HS,NOPROTECT
#use delay(clock=4000000)
// Khai bao LCD
#define rs PIN_A2
#define rw PIN_A1
#define stb PIN_A0
#byte db = 0x08
#define Amode 0x00
#define Dmode 0x0F
#include
#use I2C(slave, sda=PIN_C4, scl=PIN_C3, address=0xa0, NOFORCE_SW)
// Chuong trinh chinh
void khoitao();
void main(void)
{
int indata;
set_tris_d(Dmode);
set_tris_a(Amode);
// set_tris_c(0x99);
lcd_init();
lcd_clear();
lcd_data("Start I2C test");
delay_ms(2000);
lcd_clear();
while(1)
{
if(i2c_poll()){
indata=i2c_read();
lcd_data(indata);
}
}
}
12.1.2. lcd1_lib
///////////////////////////////////////////////
// LCD control Library
// functions are below
// lcd_init()-------- initialize
// lcd_ready()------- busy check
// lcd_cmd(cmd)------ send command
// lcd_data(string)-- display string
// lcd_clear() ------ clear display
//////////////////////////////////////////////
/////////// lcd ready check function
int lcd_ready(){
int high,low;
set_tris_b(Bmode | 0xF0); //upper is input
output_low(rs);
output_high(rw); //read mode
output_high(stb);
high= PORTB& 0xF0; //input upper
output_low(stb);
output_high(stb);
low=PORTB & 0xF0; //input lower
output_low(stb);
set_tris_b(Bmode);
return(high | (low>>4)); //end check
}
////////// lcd display data function
void lcd_data(int asci){
PORTB = asci; //set upper data
output_low(rw); //set write
output_high(rs); //set rs high
output_high(stb); //strobe
output_low(stb);
asci=asci<<4;
PORTB = asci; //set lower data
output_high(stb); //strobe
output_low(stb);
while(bit_test(lcd_ready(),7));
}
////////// lcd command out function
void cmdout(int cmd){
PORTB = cmd; //set upper data
output_low(rw); //set write
output_low(rs); //set rs low
output_high(stb); //strobe
output_low(stb);
cmd=cmd<<4;
PORTB = cmd; //set lower data
output_high(stb); //strobe
output_low(stb);
}
void lcd_cmd(int cmd){
cmdout(cmd);
while(bit_test(lcd_ready(),7)); //end check
}
////////// lcd display clear function
void lcd_clear(){
lcd_cmd(1); //initialize command
}
///////// lcd initialize function
void lcd_incmd(int cmd){
PORTB = cmd; //mode command
output_low(rw); //set write
output_low(rs); //set rs low
output_high(stb); //strobe
output_low(stb);
delay_us(100);
}
void lcd_init(){
delay_ms(15);
lcd_incmd(0x30); //8bit mode set
delay_ms(5);
lcd_incmd(0x30); //8bit mode set
delay_ms(1);
lcd_incmd(0x30); //8bit mode set
lcd_incmd(0x20); //4bit mode set
lcd_cmd(0x2E); //DL=0 4bit mode
lcd_cmd(0x08); //disolay off C=D=B=0
lcd_cmd(0x0D); //display on C=D=1 B=0
lcd_cmd(0x06); //entry I/D=1 S=0
}
12.1.3. lcd2_lib
///////////////////////////////////////////////
// LCD control Library
// functions are below
// lcd_init()-------- initialize
// lcd_ready()------- busy check
// lcd_cmd(cmd)------ send command
// lcd_data(string)-- display string
// lcd_clear() ------ clear display
//////////////////////////////////////////////
/////////// lcd ready check function
int lcd_ready(){
int high,low;
set_tris_d(Dmode | 0xF0); //upper is input ------------
output_low(rs);
output_high(rw); //read mode
output_high(stb);
high=db & 0xF0; //input upper
output_low(stb);
output_high(stb);
low=db & 0xF0; //input lower
output_low(stb);
set_tris_d(Dmode);//---------------------------------------
return(high | (low>>4)); //end check
}
////////// lcd display data function
void lcd_data(int asci){
db = asci; //set upper data
output_low(rw); //set write
output_high(rs); //set rs high
output_high(stb); //strobe
output_low(stb);
asci=asci<<4;
db = asci; //set lower data
output_high(stb); //strobe
output_low(stb);
while(bit_test(lcd_ready(),7));
}
////////// lcd command out function
void cmdout(int cmd){
db = cmd; //set upper data
output_low(rw); //set write
output_low(rs); //set rs low
output_high(stb); //strobe
output_low(stb);
cmd=cmd<<4;
db = cmd; //set lower data
output_high(stb); //strobe
output_low(stb);
}
void lcd_cmd(int cmd){
cmdout(cmd);
while(bit_test(lcd_ready(),7)); //end check
}
////////// lcd display clear function
void lcd_clear(){
lcd_cmd(1); //initialize command
}
///////// lcd initialize function
void lcd_incmd(int cmd){
db = cmd; //mode command
output_low(rw); //set write
output_low(rs); //set rs low
output_high(stb); //strobe
output_low(stb);
delay_us(100);
}
void lcd_init(){
delay_ms(15);
lcd_incmd(0x30); //8bit mode set
delay_ms(5);
lcd_incmd(0x30); //8bit mode set
delay_ms(1);
lcd_incmd(0x30); //8bit mode set
lcd_incmd(0x20); //4bit mode set
lcd_cmd(0x2E); //DL=0 4bit mode
lcd_cmd(0x08); //disolay off C=D=B=0
lcd_cmd(0x0D); //display on C=D=1 B=0
lcd_cmd(0x06); //entry I/D=1 S=0
}
12.2. Giao tiếp RS232
Serial Port - lập trình giao tiếp nối tiếp
Tôi xin copy tất cả các bài của tôi vào box này để cho tổng quát hơn giới thiệu về giao tiếp nối tiếp qua Serial Port như RS-232, RS-485. Hi vọng là cho các bạn có kiến thức đầy đủ về lập trình nối tiếp nói chung và qua RS232, RS-485 nói riêng.
Giới thiệu giao tiếp cổng com - chapter1
Tôi xin giới thiệu cho các bạn chi tiết các thông tin, cách lập trình truyền thông nối tiếp dùng chuẩn RS-232 và RS-485.
Có thể có nhiều bạn đã biết rồi hoặc là chưa biết nhưng tôi mong rằng sẽ bổ sung cho các bạn một số điều cơ bản.
Tất cả mọi vấn đề tôi dịch từ cuốn Serial_complete của Jan Axelson và thực tế lập trình truyền thông giao tiếp với vdk AT89C51( một loại vi điều khiển đơn giản). Hi vọng các vấn đề tôi đưa ra sẽ làm các bạn môt phần nào hiểu biết thêm về cổng thông dụng này cổng Comm( communicactions).
Do thời gian không có nhiều vừa làm vừa ôn thi nên mỗi ngày tôi sẽ up lên từng vấn đề một. Mong các bạn góp ý thêm. Tôi làm cái này không có ý qua mặt các cao thủ, mong các cao thủ bỏ quá cho. Các bạn có thể có thêm nhiều ví dụ khi vào trang web http://www.lvr.com
Chia sẻ với bạn bè của bạn: |