此篇利用GPIO造出I2C訊號,並操作16x2 LCD,使用的16x2 LCD為I2C控制類型,如下所示,
程式部分是以Microchip MCU例子,但觀念可以用在其他廠牌MCU,只要改變週遭IO配置就可以,
1. GPIO程式
.h部份
/* RB8 */
#define IO_RB8_SetDigitalOutput() TRISBbits.TRISB8 = 0;
#define IO_RB8_SetDigitalInput() TRISBbits.TRISB8 = 1;
#define IO_RB8_GetValue() PORTBbits.RB8
#define IO_RB8_SetLow() LATBbits.LATB8 = 0;
#define IO_RB8_SetHigh() LATBbits.LATB8 = 1;
#define IO_RB8_Toggle() LATBbits.LATB8 = ~LATBbits.LATB8;
#define IO_RB8_SetPushPull() ODCBbits.ODCB8 = 0;
#define IO_RB8_SetOpenDrain() ODCBbits.ODCB8 = 1;
/* RB9 */
#define IO_RB9_SetDigitalOutput() TRISBbits.TRISB9 = 0;
#define IO_RB9_SetDigitalInput() TRISBbits.TRISB9 = 1;
#define IO_RB9_GetValue() PORTBbits.RB9
#define IO_RB9_SetLow() LATBbits.LATB9 = 0;
#define IO_RB9_SetHigh() LATBbits.LATB9 = 1;
#define IO_RB9_Toggle() LATBbits.LATB9 = ~LATBbits.LATB9;
#define IO_RB9_SetPushPull() ODCBbits.ODCB9 = 0;
#define IO_RB9_SetOpenDrain() ODCBbits.ODCB9 = 1;
.c部份
/* LCD1206 GPIO Config */
/* SCL RB8 */
IO_RB8_SetDigitalOutput();
IO_RB8_SetPushPull();
IO_RB8_SetLow();
/* SDA RB9 */
IO_RB9_SetDigitalOutput();
IO_RB9_SetPushPull();
IO_RB9_SetLow();
2. I2C GPIO程式
.h部份
#define SCL LATBbits.LATB8
#define SDA LATBbits.LATB9
#define SDA_Output() TRISBbits.TRISB9 = 0;
#define SDA_Input() TRISBbits.TRISB9 = 1;
#define SDA_READ() PORTBbits.RB9
/* I2C Start */
void I2C_Start(void);
/* I2C Stop */
void I2C_Stop(void);
/* I2C Ack */
void I2C_Ack(void);
/* I2C NAck */
void I2C_NAck(void);
/* I2C Wait Ack */
uint8_t I2C_WaitAck(void);
/* I2C Send Byte */
void I2C_SendByte(uint8_t byte);
/* I2C Read Byte */
uint8_t I2C_ReadByte(void);
.c部份
/*
Name: I2C Start
Version: V1.0
Author: Michael Cheng
Created Date:
Updated Data: N/A
Description:
Updated Record:
*/
void I2C_Start(void){
SDA_Output();
delay_us(2);
SCL = 1;
SDA = 1;
delay_us(2);
SDA = 0;
delay_us(2);
SCL = 0;
}
/*
Name: I2C Stop
Version: V1.0
Author: Michael Cheng
Created Date:
Updated Data: N/A
Description:
Updated Record:
*/
void I2C_Stop(void){
SDA_Output();
SDA = 0;
SCL = 0;
delay_us(2);
SCL = 1;
delay_us(2);
SDA = 1;
}
/*
Name: I2C Ack
Version: V1.0
Author: Michael Cheng
Created Date:
Updated Data: N/A
Description:
Updated Record:
*/
void I2C_Ack(void){
SDA_Output();
SCL = 0;
SDA = 0;
delay_us(2);
SCL = 1;
delay_us(2);
SCL = 0;
delay_us(2);
SDA = 1;
}
/*
Name: I2C NAck
Version: V1.0
Author: Michael Cheng
Created Date:
Updated Data: N/A
Description:
Updated Record:
*/
void I2C_NAck(void){
SDA_Output();
SCL = 0;
SDA = 1;
delay_us(2);
SCL = 1;
delay_us(2);
SCL = 0;
delay_us(2);
}
/*
Name: I2C Wait Ack
Version: V1.0
Author: Michael Cheng
Created Date:
Updated Data: N/A
Description:
Updated Record:
*/
uint8_t I2C_WaitAck(void){
uint8_t errTime=0,readAck=0;
SDA_Input();
delay_us(2);
SCL = 1;
while(1){
readAck = SDA_READ();
if(readAck==1){
errTime++;
if(errTime>10){
return 1;
}
}
if(readAck==0){
delay_us(2);
SCL = 0;
return 0;
}
}
}
/*
Name: I2C Send Byte
Version: V1.0
Author: Michael Cheng
Created Date:
Updated Data: N/A
Description:
Updated Record:
*/
void I2C_SendByte(uint8_t byte){
uint8_t i=0;
SDA_Output();
SCL = 0;
for (i=0; i<8; i++){
SDA = (byte&0x80)>>7;
byte <<= 1;
delay_us(1);
SCL = 1;
delay_us(2);
SCL = 0;
delay_us(1);
}
}
/*
Name: I2C Read Byte
Version: V1.0
Author: Michael Cheng
Created Date:
Updated Data: N/A
Description:
Updated Record:
*/
uint8_t I2C_ReadByte(void){
uint8_t i=0,rxData=0,receive=0;
SDA_Input();
for(i=0; i<8; i++){
SCL = 0;
delay_us(2);
SCL = 1;
receive<<=1;
rxData = SDA_READ();
if(rxData){
receive++;
}
delay_us(2);
}
return receive;
}
3. LCD1206程式
.h部份
/* LCD1206 Init */
void LCD1206_Init(void);
/* LCD1206 Set Cursor */
void LCD1206_SetCursor(uint8_t x, uint8_t y);
/* LCD1206 String */
void LCD1206_String(uint8_t *str, uint16_t length);
/* LCD1206顯示數字 */
void LCD1206_ShowNum(uint32_t num, uint16_t length);
/* LCD1206 Clear */
void LCD1206_Clear(void);
/* LCD1206 Command Write */
void LCD1206_CommandWrite(uint8_t cmd);
/* LCD1206 Data Write */
void LCD1206_DataWrite(uint8_t data);
/* LCD1206 Byte Write */
void LCD1206_ByteWrite(uint8_t address, uint8_t *writeData);
.c部份
/*
Name: LCD1206 Init
Version: V1.0
Author: Michael Cheng
Created Date:
Updated Data: N/A
Description:
Updated Record:
*/
void LCD1206_Init(void){
delay_ms(150);
LCD1206_CommandWrite(0x02);
//16 *2顯示,5 *7點陣,4位數據口
LCD1206_CommandWrite(0x28);
//開顯示,光標關閉
LCD1206_CommandWrite(0x0C);
LCD1206_CommandWrite(0x80);
}
/*
Name: LCD1206 Set Cursor
Version: V1.0
Author: Michael Cheng
Created Date:
Updated Data: N/A
Description:
Updated Record:
*/
void LCD1206_SetCursor(uint8_t x, uint8_t y){
uint8_t addr=0;
if (y == 0){
addr = 0x00 + x;
}else{
addr = 0x40 + x;
}
LCD1206_CommandWrite(addr | 0x80);
}
/*
Name: LCD1206 String
Version: V1.0
Author: Michael Cheng
Created Date:
Updated Data: N/A
Description:
Updated Record:
*/
void LCD1206_String(uint8_t *str, uint16_t length){
uint16_t i=0;
for(i=0; i<length; i++){
LCD1206_DataWrite(*(str + i));
}
}
/*
Name: LCD1206顯示數字
Version: V1.0
Author: Michael Cheng
Created Date:
Updated Data: N/A
Description:
uint32_t num: 數字
uint16_t length: 長度
Updated Record:
*/
void LCD1206_ShowNum(uint32_t num, uint16_t length){
uint8_t i=0,temp=0,enshow=0;
for(i=0; i<length; i++){
temp = (num/mypow(10,length-i-1))%10;
if(enshow==0&&i<(length-1)){
if(temp==0){
continue;
}else{
enshow = 1;
}
}
LCD1206_DataWrite(temp + '0');
}
}
/*
Name: LCD1206 Clear
Version: V1.0
Author: Michael Cheng
Created Date:
Updated Data: N/A
Description:
Updated Record:
*/
void LCD1206_Clear(void){
LCD1206_CommandWrite(0x01);
}
/*
Name: LCD1206 Command Write
Version: V1.0
Author: Michael Cheng
Created Date:
Updated Data: N/A
Description:
Updated Record:
*/
void LCD1206_CommandWrite(uint8_t cmd){
uint8_t data_u=0, data_l=0;
uint8_t data_t[4];
data_u = cmd&0xF0;
data_l = (cmd<<4)&0xF0;
data_t[0] = data_u | 0x0C; //en=1, rs=0
data_t[1] = data_u | 0x08; //en=0, rs=0
data_t[2] = data_l | 0x0C; //en=1, rs=0
data_t[3] = data_l | 0x08; //en=0, rs=0
LCD1206_ByteWrite(0x4E, data_t);
}
/*
Name: LCD1206 Data Write
Version: V1.0
Author: Michael Cheng
Created Date:
Updated Data: N/A
Description:
Updated Record:
*/
void LCD1206_DataWrite(uint8_t data){
uint8_t data_u=0, data_l=0;
uint8_t data_t[4];
data_u = data&0xF0;
data_l = (data<<4)&0xF0;
data_t[0] = data_u | 0x0D; //en=1, rs=1
data_t[1] = data_u | 0x09; //en=0, rs=1
data_t[2] = data_l | 0x0D; //en=1, rs=1
data_t[3] = data_l | 0x09; //en=0, rs=1
LCD1206_ByteWrite(0x4E, data_t);
}
/*
Name: LCD1206 Byte Write
Version: V1.0
Author: Michael Cheng
Created Date:
Updated Data: N/A
Description:
Updated Record:
*/
void LCD1206_ByteWrite(uint8_t address, uint8_t *writeData){
uint8_t i=0;
I2C_Start();
I2C_SendByte(address);
I2C_WaitAck();
for(i=0; i<4; i++){
I2C_SendByte(*(writeData + i));
I2C_WaitAck();
}
I2C_Stop();
}
4. program_tools程式
.h部份
#define delay_mcnt 7937 // Delay Coefficient
/* Delay us */
void delay_us(unsigned int n);
/* Delay Millisecond */
void delay_ms(unsigned int n);
/* 平方函數 */
uint32_t mypow(uint8_t m, uint8_t n);
.c部份
/*
Name: Delay us
Version: V1.0
Author: Michael Cheng
Created Date: 2018/10/24
Updated Data: N/A
Description:
已us為單位做延時操作
Updated Record:
*/
void delay_us(unsigned int n){
unsigned int dly;
while(n!=0){
dly=delay_mcnt/1000; while(dly!=0) dly--;
n--;
}
}
/*
Name: Delay Millisecond
Version: V1.0
Author: Michael Cheng
Created Date: 2018/10/24
Updated Data: N/A
Description:
已ms為單位做延時操作
unsigned int n: 設置延時時間
Updated Record:
*/
void delay_ms(unsigned int n){
unsigned int dly;
while(n!=0){
dly=delay_mcnt; while(dly!=0) dly--;
n--;
}
}
/*
Name: 平方函數
Version: V1.0
Author: Michael Cheng
Created Date:
Updated Data: N/A
Description:
Updated Record:
*/
uint32_t mypow(uint8_t m, uint8_t n){
uint32_t result=1;
while(n--){
result*=m;
}
return result;
}
5. main程式
LCD1206_SetCursor(0, 0);
LCD1206_String((uint8_t*)"Hello, World!", 13);
LCD1206_SetCursor(0, 1);
LCD1206_ShowNum(12345, 5);
留言列表