close

256317.jpg

此篇利用GPIO造出I2C訊號,並操作16x2 LCD,使用的16x2 LCD為I2C控制類型,如下所示,

408766.jpg

408767.jpg

程式部分是以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);

arrow
arrow
    文章標籤
    MCU GPIO UART 16x2 LCD
    全站熱搜
    創作者介紹
    創作者 鄭智遠 的頭像
    鄭智遠

    Michael_Jheng的部落格

    鄭智遠 發表在 痞客邦 留言(0) 人氣()