这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 国产MCU » 【STC32G12K128】使用I2C外设驱动I2C接口的LCD显示的例程

共1条 1/1 1 跳转至

【STC32G12K128】使用I2C外设驱动I2C接口的LCD显示的例程

专家
2026-04-03 22:44:33     打赏

本例程使用STC32G12K128最小核心开发板,

无标题.png

使用的LCD显示屏:

LCD.png

I2C接口模式,本身提供汉字字库,可以通过和ROM有关的四个SPI接口线获取字符的点阵数据。原理图:

原理图.png

处理代码:

main.c


//#include "COMM/stc.h"    //调用头文件
#include "stdio.h"
#include "usart2.h"
// 系统使用11.0592MHz烧录,如果修改,为了串口正常工作,要修改 Baudrate1 和 MAIN_Fosc的定义值
// 系统主频=12MHz场合,I2C的频率=800KHz,可以显示
// 系统主频=18MHz场合,I2C的频率=1.25MHz,可以显示
// 系统主频=20MHz场合,I2C的频率=1.25MHz,可以显示
// 系统主频=22MHz场合,I2C的频率=1.5MHz, 不能显示
// LCD模块的 IIC 接口引脚功能 
//  1       ROM_IN                   LCD模块的字库数据输入
//  2       ROM_OUT                  LCD模块的字库点阵数据输入出
//  3       ROM_SCK                  LCD模块的字库访问用SCK
//  4       ROM_CS                   LCD模块的字库访问许可
//  5       LEDA   背光电源          背光电源正极,同 VDD 电压(5V 或 3.3V)
//  6       VSS    供电电源负极      供电电源负极 
//  7       VDD    供电电源正极      供电电源正极(注意:购买时须选择 3.3V 或者是 5V 供电)
//  8       A0(RS) 寄存器选择信号    IIC 接口,悬空或接 VDD 
//  9       RST    复位              低电平复位,复位完成后,回到高电平,液晶模块开始工作
// 10       CS     片选              IIC 接口,此引脚接 VSS 
// 11       D7     I/0               IIC 接口,此引脚是从属地址接 VSS 
// 12       D6     I/0               IIC 接口,此引脚是从属地址接 VSS 
// 13       D5     I/0               IIC 接口,悬空或接 VDD 
// 14       D4     I/0               IIC 接口,悬空或接 VDD 
// 15-17    D3-D1(SDA) I/0           串行数据(D1、D2、D3 短接一起作为 SDA) 
// 18       D0(SCK) I/0              串行时钟 
// 19       RD(E)  使能信号          IIC 接口,悬空或接 VDD 
// 20       WR     读/写             IIC 接口,悬空或接 VDD 
sbit LCD_RST = P1^0;     // RST        
// 与LCD的接口,与I2C外设重合,目的是为了能使用I2C外设
sbit LCD_SCL = P1^5;    // 串行时钟   
sbit LCD_SDA = P1^4;    // 串行数据   
// 访问字库用的引脚(与SPI外设重合,目的是为后面改成SPI模式)
sbit Rom_IN  = P2^3; /*字库 IC 接口定义:Rom_IN 就是字库 IC 的 SI*/ 
sbit Rom_OUT = P2^4; /*字库 IC 接口定义:Rom_OUT 就是字库 IC 的 SO*/ 
sbit Rom_SCK = P2^5; /*字库 IC 接口定义:Rom_SCK 就是字库 IC 的 SCK*/ 
sbit Rom_CS  = P2^2; /*字库 IC 接口定义 Rom_CS 就是字库 IC 的 CS#*/ 
 
#define uchar unsigned char 
#define uint unsigned int 
#define ulong unsigned long 
#define ADDR 0x78
#define USE_I2C_DEV 1
#define DELAY 4000000000
// 串口1用
#define Baudrate1   (65536 - MAIN_Fosc / 115200 / 4)
#define UART1_BUF_LENGTH    128
uchar  TX1_Cnt;    //发送计数
uchar  RX1_Cnt;    //接收计数
bit B_TX1_Busy; //发送忙标志
uchar  RX1_Buffer[UART1_BUF_LENGTH]; //接收缓冲
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
bit  TIM_10MS_Flag;      //10ms的标志位 
u16 Tme_CountDown = 0;    //全局变量
u8   dat[32];
void sys_init();  //函数声明
void delay_ms(u16 ms);  //unsigned int 
void sys_init() {
    WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度
    P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
//    P3M0 = 0x00;
//    P3M1 = 0x00;
//    P3M0 &= ~0x03;
//    P3M1 |= 0x03;
//    //设置USB使用的时钟源
//    IRC48MCR = 0x80;    //使能内部48M高速IRC
//    while (!(IRC48MCR & 0x01));  //等待时钟稳定
//    USBCLK = 0x00;  //使用CDC功能需要使用这两行,HID功能禁用这两行。
//    USBCON = 0x90;
}
/*延时:1 毫秒的 i 倍*/ 
void delay_ms(unsigned long i) { 
 int j,k; 
 for(j=0;j<i;j++) 
 for(k=0;k<110;k++); 
} 
 
/*延时:1us 的 i 倍*/ 
void delay_us(unsigned long i) { 
 int j,k; 
 for(j=0;j<i;j++) 
 for(k=0;k<1;k++); 
} 
//==============================I2C外设用代码 BEGIN ==========================================
void I2C_Wait() {
    while (!(I2CMSST & 0x40));
    I2CMSST &= ~0x40;
}
void I2C_Start() {
    I2CMSCR = 0x01;                         //发送START命令
    I2C_Wait();
}
void I2C_SendData(char dat) {
    I2CTXD = dat;                           //写数据到数据缓冲区
    I2CMSCR = 0x02;                         //发送SEND命令
    I2C_Wait();
}
void I2C_RecvACK() {
    I2CMSCR = 0x03;                         //发送读ACK命令
    I2C_Wait();
}
char I2C_RecvData() {
    I2CMSCR = 0x04;                         //发送RECV命令
    I2C_Wait();
    return I2CRXD;
}
void I2C_SendACK() {
    I2CMSST = 0x00;                         //设置ACK信号
    I2CMSCR = 0x05;                         //发送ACK命令
    I2C_Wait();
}
void I2C_SendNAK() {
    I2CMSST = 0x01;                         //设置NAK信号
    I2CMSCR = 0x05;                         //发送ACK命令
    I2C_Wait();
}
void I2C_Stop()
{
    I2CMSCR = 0x06;                         //发送STOP命令
    I2C_Wait();
}
//==============================I2C外设用代码 END ==========================================
//==============================I2C模拟用代码 BEGIN ==========================================
/*START FLAG*/ 
void start_flag() { 
    LCD_SCL=1; 
    LCD_SDA=1; /*START FLAG*/ 
    LCD_SDA=0; /*START FLAG*/ 
}
/*STOP FLAG*/ 
void stop_flag() { 
    LCD_SCL=1; 
    LCD_SDA=0;
    LCD_SDA=1;
}
void transfer(int data1) { 
    int i; 
    for(i=0;i<8;i++) { 
        LCD_SCL=0; 
        if(data1&0x80) LCD_SDA=1; 
        else LCD_SDA=0; 
        LCD_SCL=1; 
        LCD_SCL=0; 
        data1=data1<<1; 
    } 
    LCD_SDA=0; 
    LCD_SCL=1; 
    LCD_SCL=0; 
}
 
//写命令到液晶显示模块 
void transfer_command_lcd(uchar cmd) { 
#ifndef  USE_I2C_DEV
    start_flag(); 
    transfer(0x78); 
    transfer(0x80); 
    transfer(cmd); 
    stop_flag(); 
#else
    // ================= 单字节处理模式 ========================
    I2C_Start();                            //发送起始命令
    
    I2C_SendData(ADDR);                     //发送设备地址+写命令
    I2C_RecvACK();                          // 等待ACK信号
    
    I2C_SendData(0x80);                     // 指令模式
    I2C_RecvACK();                          // 等待ACK信号
    
    I2C_SendData(cmd);                     //发送存储地址
    I2C_RecvACK();
    
    I2C_Stop();                                 //发送停止命令  
#endif
}
//写数据到液晶显示模块 
void transfer_data_lcd(uchar dat) {
#ifndef  USE_I2C_DEV
    // IO口模拟处理方式
    start_flag(); 
    transfer(0x78); 
    transfer(0xC0); 
    transfer(dat); 
    stop_flag(); 
#else
    // ================= 单字节处理模式 ========================
    I2C_Start();                            //发送起始命令
    
    I2C_SendData(ADDR);                     //发送设备地址+写命令
    I2C_RecvACK();                          // 等待ACK信号
    
    I2C_SendData(0xC0);                     // 数据模式
    I2C_RecvACK();                          // 等待ACK信号
    
    I2C_SendData(dat);                     //发送存储地址
    I2C_RecvACK();
    
    I2C_Stop();                            //发送停止命令  
#endif  
} 
 
//==============================I2C模拟用代码 END ==========================================
 
void initial_lcd() { 
    LCD_RST=0; 
    delay_ms(100); 
    LCD_RST=1; 
    delay_ms (100); 
    transfer_command_lcd(0x30); //EXT=0 
    transfer_command_lcd(0x94); //Sleep out 
    transfer_command_lcd(0x31); //EXT=1 
    transfer_command_lcd(0xD7); //Autoread disable 
    transfer_data_lcd(0X9F); // 
    transfer_command_lcd(0x32); //Analog SET 
    transfer_data_lcd(0x00); //OSC Frequency adjustment 
    transfer_data_lcd(0x01); //Frequency on booster capacitors->6KHz 
    transfer_data_lcd(0x03); //Bias=1/11 
    transfer_command_lcd(0x20); // Gray Level 
     
    transfer_data_lcd(0x01); 
    transfer_data_lcd(0x03); 
    transfer_data_lcd(0x05); 
    transfer_data_lcd(0x07); 
    transfer_data_lcd(0x09); 
    transfer_data_lcd(0x0b); 
    transfer_data_lcd(0x0d); 
    transfer_data_lcd(0x10); 
    transfer_data_lcd(0x11); 
    transfer_data_lcd(0x13); 
    transfer_data_lcd(0x15); 
    transfer_data_lcd(0x17); 
    transfer_command_lcd(0x31); //Analog SET 
    transfer_command_lcd(0xf2); //温度补偿 
    transfer_data_lcd(0x1e); //OSC Frequency adjustment 
    transfer_data_lcd(0x28); //Frequency on booster capacitors->6KHz 
    transfer_data_lcd(0x32); // 
    transfer_data_lcd(0x00); 
    transfer_data_lcd(0x01); 
    transfer_data_lcd(0x03);    
    transfer_command_lcd(0x30); //EXT=0 
    transfer_command_lcd(0x75); //Page Address setting 
    transfer_data_lcd(0X00); // XS=0 
    transfer_data_lcd(0X14); // XE=159 0x28 
    transfer_command_lcd(0x15); //Clumn Address setting 
    transfer_data_lcd(0X00); // XS=0 
    transfer_data_lcd(0Xff); // XE=256 
    transfer_command_lcd(0xBC); //Data scan direction 
    transfer_data_lcd(0x00); //MX.MY=Normal 
    transfer_data_lcd(0xA6); 
    transfer_command_lcd(0xCA); //Display Control 
    transfer_data_lcd(0X00); // 
    transfer_data_lcd(0X9F); //Duty=160 
    transfer_data_lcd(0X20); //Nline=off 
    
    transfer_command_lcd(0xF0); //Display Mode 
    transfer_data_lcd(0X10); //10=Monochrome Mode,11=4Gray 
    
    transfer_command_lcd(0x81); //EV control 
    transfer_data_lcd(0x0a); //VPR[5-0] //可设置范围 0x00~0x3f,每格电压是 0.04V 
    transfer_data_lcd(0x04); //VPR[8-6] //可设置范围 0x00~0x07 
    transfer_command_lcd(0x20); //Power control 
    transfer_data_lcd(0x0B); //D0=regulator ; D1=follower ; D3=booste, on:1 off:0 
    delay_us(100); 
    transfer_command_lcd(0xAF); //Display on 
} 
 
 
/*写 LCD 行列地址:X 为起始的列地址,Y 为起始的行地址,x_total,y_total 分别为列地址及行地址的起点到终点的差值 */ 
void lcd_address(int x,int y,x_total,y_total) { 
    x=x-1; 
    y=y+7; 
    transfer_command_lcd(0x15); //Set Column Address 
    transfer_data_lcd(x); 
    transfer_data_lcd(x+x_total-1); 
    transfer_command_lcd(0x75); //Set Page Address 
    transfer_data_lcd(y); 
    transfer_data_lcd(y+y_total-1); 
    transfer_command_lcd(0x30); 
    transfer_command_lcd(0x5c); 
} 
 
/*清屏*/ 
void clear_screen() { 
    int i,j; 
    lcd_address(1,1,256,17); 
    for(i=0;i<17;i++) { 
        for(j=0;j<256;j++) { 
            transfer_data_lcd(0x00); 
        } 
    } 
} 
 
/****送指令到晶联讯字库 IC***/ 
void send_command_to_ROM( uchar datu ) { 
    uchar i; 
    for(i=0;i<8;i++ ) { 
        if(datu&0x80) 
            Rom_IN = 1; 
        else 
            Rom_IN = 0; 
        datu = datu<<1; 
        Rom_SCK=0; 
        Rom_SCK=1; 
        delay_us(1); 
    } 
} 
 
/****从晶联讯字库 IC 中取汉字或字符数据(1 个字节)***/ 
static uchar get_data_from_ROM(void) { 
    uchar i; 
    uchar ret_data=0; 
    Rom_SCK=1; 
    for(i=0;i<8;i++) { 
        Rom_OUT=1; 
        Rom_SCK=0; 
        ret_data>>=1; 
        
        if( Rom_OUT ) 
            ret_data+=0x80; 
        else 
            ret_data=ret_data+0; 
        Rom_SCK=1; 
        delay_us(1); 
    } 
    return(ret_data); 
} 
 
 
//从指定地址读出数据写到液晶屏指定(page,column)座标中 
void get_and_write_8x16(ulong fontaddr, uchar column, uchar page) { 
    uchar i,j,disp_data; 
    Rom_CS = 0; 
    send_command_to_ROM(0x03); 
    send_command_to_ROM((fontaddr&0xff0000)>>16); //地址的高 8 位,共 24 位 
    send_command_to_ROM((fontaddr&0xff00)>>8); //地址的中 8 位,共 24 位 
    send_command_to_ROM(fontaddr&0xff); //地址的低 8 位,共 24 位 
    lcd_address(column,page,8,2); 
    for(j=0;j<2;j++) { 
        for(i=0; i<8; i++ ) { 
            disp_data=get_data_from_ROM(); 
            transfer_data_lcd(disp_data); //写数据到 LCD,每写完 1 字节的数据后列地址自动加 1 
        } 
    } 
    Rom_CS=1; 
} 
 
void get_and_write_12x24(ulong fontaddr, uchar column, uchar page) { 
    uchar i,j,disp_data; 
    Rom_CS = 0; 
    send_command_to_ROM(0x03); 
    send_command_to_ROM((fontaddr&0xff0000)>>16); //地址的高 8 位,共 24 位 
    send_command_to_ROM((fontaddr&0xff00)>>8); //地址的中 8 位,共 24 位 
    send_command_to_ROM(fontaddr&0xff); //地址的低 8 位,共 24 位 
    lcd_address(column,page,16,3); 
    for(j=0;j<3;j++) { 
        for(i=0; i<16; i++ ) { 
            disp_data=get_data_from_ROM(); 
            transfer_data_lcd(disp_data); //写数据到 LCD,每写完 1 字节的数据后列地址自动加 1 
        } 
    } 
    Rom_CS=1; 
} 
 
void get_and_write_16x32(ulong fontaddr, uchar column, uchar page) { 
    uchar i,j,disp_data; 
    Rom_CS = 0; 
    send_command_to_ROM(0x03); 
    send_command_to_ROM((fontaddr&0xff0000)>>16); //地址的高 8 位,共 24 位 
    send_command_to_ROM((fontaddr&0xff00)>>8); //地址的中 8 位,共 24 位 
    send_command_to_ROM(fontaddr&0xff); //地址的低 8 位,共 24 位 
    lcd_address(column,page,16,4); 
    for(j=0;j<4;j++) { 
        for(i=0; i<16; i++ ) { 
            disp_data=get_data_from_ROM(); 
            transfer_data_lcd(disp_data); //写数据到 LCD,每写完 1 字节的数据后列地址自动加 1 
        } 
    } 
    Rom_CS=1; 
} 
 
//从指定地址读出数据写到液晶屏指定(page,column)座标中 
void get_and_write_16x16(ulong fontaddr, uchar column, uchar page) { 
    uchar i,j,disp_data; 
    Rom_CS = 0; 
    send_command_to_ROM(0x03); 
    send_command_to_ROM((fontaddr&0xff0000)>>16); //地址的高 8 位,共 24 位 
    send_command_to_ROM((fontaddr&0xff00)>>8); //地址的中 8 位,共 24 位 
    send_command_to_ROM(fontaddr&0xff); //地址的低 8 位,共 24 位 
    lcd_address(column,page,16,2); 
    for(j=0;j<2;j++) { 
        for(i=0; i<16; i++ ) { 
            disp_data=get_data_from_ROM(); 
            transfer_data_lcd(disp_data); //写数据到 LCD,每写完 1 字节的数据后列地址自动加 1 
        } 
    } 
    Rom_CS=1; 
} 
 
//从指定地址读出数据写到液晶屏指定(page,column)座标中 
void get_and_write_24x24(ulong fontaddr, uchar column, uchar page) { 
    uchar i,j,disp_data; 
    Rom_CS = 0; 
    send_command_to_ROM(0x03); 
    send_command_to_ROM((fontaddr&0xff0000)>>16); //地址的高 8 位,共 24 位 
    send_command_to_ROM((fontaddr&0xff00)>>8); //地址的中 8 位,共 24 位 
    send_command_to_ROM(fontaddr&0xff); //地址的低 8 位,共 24 位 
    lcd_address(column,page,24,3); 
    for(j=0;j<3;j++) { 
        for(i=0; i<24; i++ ) { 
            disp_data=get_data_from_ROM(); 
            transfer_data_lcd(disp_data); //写数据到 LCD,每写完 1 字节的数据后列地址自动加 1 
        } 
    } 
    Rom_CS=1; 
} 
 
//从指定地址读出数据写到液晶屏指定(page,column)座标中 
void get_and_write_32x32(ulong fontaddr,uchar column, uchar page) { 
    uchar i,j,disp_data; 
    Rom_CS = 0; 
    send_command_to_ROM(0x03); 
    send_command_to_ROM((fontaddr&0xff0000)>>16); //地址的高 8 位,共 24 位 
    send_command_to_ROM((fontaddr&0xff00)>>8); //地址的中 8 位,共 24 位 
    send_command_to_ROM(fontaddr&0xff); //地址的低 8 位,共 24 位 
    lcd_address(column,page,32,4); 
    for(j=0;j<4;j++) { 
        for(i=0; i<32; i++ ) { 
            disp_data=get_data_from_ROM(); 
            transfer_data_lcd(disp_data); //写数据到 LCD,每写完 1 字节的数据后列地址自动加 1 
        } 
    } 
    Rom_CS=1; 
} 
 
//**************************************************************** 
 
ulong fontaddr=0; 
void display_GB2312_16x16_string(uchar column, uchar page, uchar *text) { 
    uchar i= 0;uint temp1,temp2; 
    temp1=column; 
    temp2=page; 
    while((text[i]>0x00)) { 
        if(((text[i]>=0xb0) &&(text[i]<=0xf7))&&(text[i+1]>=0xa1)) { 
            //国标简体(GB2312)汉字在晶联讯字库 IC 中的地址由以下公式来计算: 
            //Address = ((MSB - 0xB0) * 94 + (LSB - 0xA1)+ 846)*32+ BaseAdd;BaseAdd=0 
            //由于担心 8 位单片机有乘法溢出问题,所以分三部取地址 
            fontaddr = (text[i]- 0xb0)*94; 
            fontaddr += (text[i+1]-0xa1)+846; 
            fontaddr = (ulong)(fontaddr*32); 
            fontaddr = (ulong)(fontaddr+0x2c9d0); 
            get_and_write_16x16(fontaddr,column,page); //从指定地址读出数据写到液晶屏指定(page,column)座标中 
            i+=2; 
            column+=16; 
            if ((temp2<=15&&temp1<=256)&&column>248) { 
                //自动换行,当遇到奇数个字母或符号就提前 8 个点 
                //设成符>256 时当有奇数个字符时就会显半个汉字,因为一个字符只占 8 个点(一个字节) 
                column=1; 
                page+=2; 
                if (page>15)column=1; 
            } 
        } else if(((text[i]>=0xa1) &&(text[i]<=0xa3))&&(text[i+1]>=0xa1)) { 
            //国标简体(GB2312)15x16 点的字符在晶联讯字库 IC 中的地址由以下公式来计算: 
            //Address = ((MSB - 0xa1) * 94 + (LSB - 0xA1))*32+ BaseAdd;BaseAdd=0 
            //由于担心 8 位单片机有乘法溢出问题,所以分三部取地址 
            fontaddr = (text[i]- 0xa1)*94; 
            fontaddr += (text[i+1]-0xa1); 
            fontaddr = (ulong)(fontaddr*32); 
            fontaddr = (ulong)(fontaddr+0x2c9d0); 
            get_and_write_16x16(fontaddr,column,page); //从指定地址读出数据写到液晶屏指定(page,column)座标中 
            i+=2; 
            column+=16; 
            if ((temp2<=15&&temp1<=256)&&column>248) { 
                //自动换行,当遇到奇数个字母或符号就提前 8 个点 
                //设成符>128 时当有奇数个字符时就会显半个汉字,因为一个字符只占 8 个点(一个字节) 
                column=1; 
                page+=2; 
                if (page>15)column=1; 
            } 
        } else if((text[i]>=0x20) &&(text[i]<=0x7e)) { 
            fontaddr = (text[i]- 0x20); 
            fontaddr = (unsigned long)(fontaddr*16); 
            fontaddr = (unsigned long)(fontaddr+0x1dd780); 
            get_and_write_8x16(fontaddr,column,page); //从指定地址读出数据写到液晶屏指定(page,column)座标中 
            i+=1; 
            column+=8; 
            if ((temp1<=15&&temp2<=256)&&column>248) { 
                //自动换行,当遇到奇数个字母或符号就提前 8 个点 
                //设成符>128 时当有奇数个字符时就会显半个汉字,因为一个字符只占 8 个点(一个字节) 
                column=1; 
                page+=2; 
                if (page>15)column=1; 
            } 
        } else {
            i++; 
        }
    } 
} 
 
//**************************************************************** 
void display_GB2312_24x24_string(uchar column,uchar page,uchar *text) { 
    uchar i= 0;uint temp1,temp2; 
    temp1=column; 
    temp2=page; 
    while((text[i]>0x00))     { 
        if(((text[i]>=0xb0) &&(text[i]<=0xf7))&&(text[i+1]>=0xa1))         { 
            //国标简体(GB2312)汉字在晶联讯字库 IC 中的地址由以下公式来计算: 
            //Address = ((MSB - 0xB0) * 94 + (LSB - 0xA1)+ 846)*32+ BaseAdd;BaseAdd=0 
            //由于担心 8 位单片机有乘法溢出问题,所以分三部取地址 
            fontaddr = (text[i]- 0xb0)*94; 
            fontaddr += (text[i+1]-0xa1)+846; 
            fontaddr = (ulong)(fontaddr*72); 
            fontaddr = (ulong)(fontaddr+0X068190); 
            get_and_write_24x24(fontaddr,column,page); //从指定地址读出数据写到液晶屏指定(page,column)座标中 
            i+=2; 
            column+=24; 
        }         else if(((text[i]>=0xa1) &&(text[i]<=0xa9))&&(text[i+1]>=0xa1))         { 
            //国标简体(GB2312)15x16 点的字符在晶联讯字库 IC 中的地址由以下公式来计算: 
            //Address = ((MSB - 0xa1) * 94 + (LSB - 0xA1))*32+ BaseAdd;BaseAdd=0 
            //由于担心 8 位单片机有乘法溢出问题,所以分三部取地址 
            fontaddr = (text[i]- 0xa1)*94; 
            fontaddr += (text[i+1]-0xa1); 
            fontaddr = (ulong)(fontaddr*72); 
            fontaddr = (ulong)(fontaddr+0X068190); 
            get_and_write_24x24(fontaddr,column,page); //从指定地址读出数据写到液晶屏指定(page,column)座标中 
            i+=2; 
            column+=24; 
        }         else if((text[i]>=0x20) &&(text[i]<=0x7e))   { 
            fontaddr = (text[i]- 0x20); 
            fontaddr = (unsigned long)(fontaddr*48); 
            fontaddr = (unsigned long)(fontaddr+0x1dff00); 
            get_and_write_12x24(fontaddr,column,page); //从指定地址读出数据写到液晶屏指定(page,column)座标中 
            i+=1; 
            column+=12; 
        }  else {
            i++; 
        }
    } 
} 
 
//**************************************************************** 
void display_GB2312_32x32_string(uchar column,uchar page,uchar *text) { 
    uchar i= 0;uint temp1,temp2; 
    temp1=column; 
    temp2=page; 
    while((text[i]>0x00)) { 
        if(((text[i]>=0xb0) &&(text[i]<=0xf7))&&(text[i+1]>=0xa1)) { 
            //国标简体(GB2312)汉字在晶联讯字库 IC 中的地址由以下公式来计算: 
            //Address = ((MSB - 0xB0) * 94 + (LSB - 0xA1)+ 846)*32+ BaseAdd;BaseAdd=0 
            //由于担心 8 位单片机有乘法溢出问题,所以分三部取地址 
            fontaddr = (text[i]- 0xb0)*94; 
            fontaddr += (text[i+1]-0xa1)+846; 
            fontaddr = (ulong)(fontaddr*128); 
            fontaddr = (ulong)(fontaddr+0xedf00); 
            get_and_write_32x32(fontaddr,column,page); //从指定地址读出数据写到液晶屏指定(page,column)座标中 
            i+=2; 
            column+=32; 
        } else if(((text[i]>=0xa1) &&(text[i]<=0xa9))&&(text[i+1]>=0xa1)) { 
            //国标简体(GB2312)15x16 点的字符在晶联讯字库 IC 中的地址由以下公式来计算: 
            //Address = ((MSB - 0xa1) * 94 + (LSB - 0xA1))*32+ BaseAdd;BaseAdd=0 
            //由于担心 8 位单片机有乘法溢出问题,所以分三部取地址 
            fontaddr = (text[i]- 0xa1)*94; 
            fontaddr += (text[i+1]-0xa1); 
            fontaddr = (ulong)(fontaddr*128); 
            fontaddr = (ulong)(fontaddr+0xedf00); 
            get_and_write_32x32(fontaddr,column,page); //从指定地址读出数据写到液晶屏指定(page,column)座标中 
            i+=2; 
            column+=32; 
        } else if((text[i]>=0x20) &&(text[i]<=0x7e)) { 
            fontaddr = (text[i]- 0x20); 
            fontaddr = (unsigned long)(fontaddr*64); 
            fontaddr = (unsigned long)(fontaddr+0x1e5a50); 
            get_and_write_16x32(fontaddr,column,page); //从指定地址读出数据写到液晶屏指定(page,column)座标中 
            i+=1; 
            column+=16; 
        } else {
            i++; 
        }
    } 
}
/*显示 256*96 点阵的图像*/ 
void disp_256x96(int x,int y,char *dp)  { 
    int i,j; 
    lcd_address(x,y,256,12); 
    for(i=0;i<12;i++)      { 
        for(j=0;j<256;j++)      { 
            transfer_data_lcd(*dp); 
            dp++; 
        } 
    } 
} 
// 串口1:P3.0,P3.1
// ==================================== 串口1 BEGIN =======================================
//========================================================================
// 函数: void PrintString1(u8 *puts)
// 描述: 串口1发送字符串函数。
// 参数: puts:  字符串指针.
//========================================================================
void PrintString1(uchar *puts)
{
    for (; *puts != 0;  puts++)     //遇到停止符0结束
    {
        SBUF = *puts;
        B_TX1_Busy = 1;
        while(B_TX1_Busy);
    }
}
//========================================================================
// 函数: void UART1_config(u8 brt)
// 描述: UART1初始化函数。
// 参数: brt: 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
//========================================================================
void UART1_config(uchar brt)
{
    /*********** 波特率使用定时器2 *****************/
    if(brt == 2) {
        S1BRT = 1;  //S1 BRT Use Timer2;
        SetTimer2Baudraye(Baudrate1);
    }
    /*********** 波特率使用定时器1 *****************/
    else {
        TR1 = 0;
        S1BRT = 0;    //S1 BRT Use Timer1;
        T1_CT = 0;    //Timer1 set As Timer
        T1x12 = 1;    //Timer1 set as 1T mode
        TMOD &= ~0x30;//Timer1_16bitAutoReload;
        TH1 = (u8)(Baudrate1 / 256);
        TL1 = (u8)(Baudrate1 % 256);
        ET1 = 0;    //禁止中断
        TR1 = 1;
    }
    /*************************************************/
    SCON = (SCON & 0x3f) | 0x40;    //UART1模式, 0x00: 同步移位输出, 0x40: 8位数据,可变波特率, 0x80: 9位数据,固定波特率, 0xc0: 9位数据,可变波特率
//  PS  = 1;    //高优先级中断
    ES  = 1;    //允许中断
    REN = 1;    //允许接收
    P_SW1 &= 0x3f;
//  P_SW1 |= 0x00;      //UART1 switch to, 0x00: P3.0 P3.1, 0x40: P3.6 P3.7, 0x80: P1.6 P1.7, 0xC0: P4.3 P4.4
    B_TX1_Busy = 0;
    TX1_Cnt = 0;
    RX1_Cnt = 0;
}
//========================================================================
// 函数: void UART1_int (void) interrupt UART1_VECTOR
// 描述: UART1中断函数。
//========================================================================
void UART1_int (void) interrupt 4 {
    if(RI) {
        RI = 0;
        RX1_Buffer[RX1_Cnt] = SBUF;
        if(++RX1_Cnt >= UART1_BUF_LENGTH)   RX1_Cnt = 0;
    }
    if(TI) {
        TI = 0;
        B_TX1_Busy = 0;
    }
}
// ==================================== 串口1 END =======================================
void main() {
    u8 i;
    char str[30];
    int temp=0;
    sys_init();              // IO口初始化
    UART1_config(2);        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
    UART2_config(2);        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
#ifdef  USE_I2C_DEV    
    // I2C 外设初始化
    I2C_S1 =0; I2C_S0 =0;   //I2C功能脚选择,00:P1.5,P1.4; 01:P2.5,P2.4; 11:P3.2,P3.3
    
    I2CCFG = 0xe0;          //使能I2C主机模式
    I2CMSST = 0x00;
#endif  
  
  
    EA = 1;          // CPU开放中断,打开总中断。
    PrintString1("STC32G UART1 Test Programme!\r\n");  //UART1发送一个字符串
    PrintString2("STC32G UART2 Test Programme!\r\n");  //UART2发送一个字符串
  
    initial_lcd(); //对液晶模块进行初始化设置 
    clear_screen(); 
    display_GB2312_16x16_string(1,1,"ABC123"); 
    display_GB2312_16x16_string(1,3,"abc01234"); 
    display_GB2312_16x16_string(1,5,"简体汉字 8X16、12X24、16X32"); 
  
    while(1) { 
    } 
}


uart2.c


#include "usart2.h" 
u8  TX2_Cnt;    //发送计数
u8  RX2_Cnt;    //接收计数
bit B_TX2_Busy; //发送忙标志
u8  RX2_Buffer[UART2_BUF_LENGTH]; //接收缓冲
bit Rec_Flag = 0;  //接受完成标志位
//========================================================================
// 函数: void UART2_config(u8 brt)
// 描述: UART2初始化函数。
// 参数: brt: 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
// 备注: 使用Timer2做波特率 : 115200
//========================================================================
void UART2_config(u8 brt) {
    if(brt == 2) {
        SetTimer2Baudraye(Baudrate2);
        S2CFG |= 0x01;     //使用串口2时,W1位必需设置为1,否则可能会产生不可预期的错误
        S2CON = (S2CON & 0x3f) | 0x40;    //UART2模式, 0x00: 同步移位输出, 0x40: 8位数据,可变波特率, 0x80: 9位数据,固定波特率, 0xc0: 9位数据,可变波特率
        ES2   = 1;         //允许中断
        S2REN = 1;         //允许接收
        S2_S  = 1;         //UART2 switch to: 0: P1.0 P1.1,  1: P4.6 P4.7
        B_TX2_Busy = 0;
        TX2_Cnt = 0;
        RX2_Cnt = 0;
    }
}
//========================================================================
// 函数: SetTimer2Baudraye(u32 dat)
// 描述: 设置Timer2做波特率发生器。
// 参数: dat: Timer2的重装值.
=================================================================
void SetTimer2Baudraye(u32 dat) {
    T2R = 0;    //Timer stop
    T2_CT = 0;  //Timer2 set As Timer
    T2x12 = 1;  //Timer2 set as 1T mode
    T2H = (u8)(dat / 256);
    T2L = (u8)(dat % 256);
    ET2 = 0;    //禁止中断
    T2R = 1;    //Timer run enable
}
//========================================================================
// 函数: void UART2_int (void) interrupt UART2_VECTOR
// 描述: UART2中断函数。
//========================================================================
void UART2_int (void) interrupt 8 {
    // 如果接受到数据
    if(S2RI) {
        S2RI = 0;    //Clear Rx flag
        RX2_Buffer[RX2_Cnt] = S2BUF;
    
    if( RX2_Buffer[RX2_Cnt]== '\n' ) {
      if( RX2_Buffer[RX2_Cnt-1]== '\r' ) {
        Rec_Flag = 1;
      }
      RX2_Cnt = 0;
    } else {
      RX2_Cnt++;
        }
    }
    if(S2TI) {
        S2TI = 0;    //Clear Tx flag
        B_TX2_Busy = 0;
    }
}
//========================================================================
// 函数: void PrintString2(u8 *puts)
// 描述: 串口2发送字符串函数。
// 参数: puts:  字符串指针.
//========================================================================
void PrintString2(u8 *puts) {
    
    // 遇到停止符0结束
    for (; *puts != 0;  puts++) {
        S2BUF = *puts;
        B_TX2_Busy = 1;
        while(B_TX2_Busy);
    }
}


串口1对应于开发板上的串口,串口2使用 P4.7 和 P4.6 。

程序运行效果:

demo.png





关键词: 菜鸟学单片机     STC32G12K128     I2C接口    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]