文章目录
- stc15 - ST7920-12864并口通讯和串口通讯的整理(在一个实现中)
- 概述
- 笔记
- 原理图
- END
stc15 - ST7920-12864并口通讯和串口通讯的整理(在一个实现中)
概述
为板子写测试程序, 整到12864 LCD这里.
STC原厂工程只提供并口通讯.
找了网上同学的串口通讯实现, 整理了一下, 将串口通讯和并口通讯放在在一个实现中.
在程序中, 轮流调用串口通讯和并口通讯来点亮ST7920-12864 LCD.
在STC官方工程上改的, 测试好使.
等下一步, 我将这个ST7920-12864实现迁移到我的出厂测试程序中, 将变量都移动到XDATA, 再节省一些data空间.
实际用的时候, 可以选串行方式或并口方式, 给初始化函数的参数不同ST7290_Init(is_ST7920_need_spi), 实现代码不用动.
笔记
// @file main.c
// @brief ST7920的基本驱动程序 根据PSB管脚状态, 来决定ST7920-12864 LCD 是并口通讯还是串口通讯
// 在STC官方工程上改的, 原版工程只能并口通讯
#define MAIN_Fosc 22118400UL //定义主时钟
#include "STC15Fxxxx.H"
sbit ST7920_RS_CS = P2 ^ 5; // ST7920-CS
sbit ST7920_RW_SID = P2 ^ 6; // ST7920-SID
sbit ST7920_E_SCLK = P2 ^ 7; // ST7920-SCLK
sbit ST7920_PSB = P2 ^ 4; // ST7920-PSB脚为 串、并通讯功能切换,PSB=1 为并口通讯, PSB = 0 为串口通讯
sbit ST7920_RESET = P2 ^ 3; // ST7920-RESET
#define ST7920_DATA_PORT P0 // 只有并口通讯才用ST7920_DATA_PORT
#define ST7920_FLAG_BUSY 0x80 //用于检测LCD状态字中的Busy标识
void delay_ms(u16 ms);
void ST7290_WriteData(u8 WDLCD, BuysC);
void ST7290_WriteCmd(u8 WCLCD, BuysC);
u8 ST7290_ReadStatus(void);
void ST7290_Init(u8 is_spi);
void ST7290_Clear(void);
void ST7290_show_text(u8 X, u8 Y, u8 code* DData);
void ST7290_show_pic(u8 code* DData);
void GPIO_init(void);
void ST7920_SPI_SendByte(u8 Dbyte);
u8 ST7920_SPI_RecvByte(void);
u8 code uctech[] = {"南通国芯微电子 "};
u8 code net[] = {" www.gxwmcu.com "};
u8 code mcu[] = {"专业制造51单片机"};
u8 code qq[] = {" QQ: 800003751 "};
//128*64点阵图形数据
code u8 gImage_gxw[1024] = { /* 0X10,0X01,0X00,0X80,0X00,0X40, */
0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,
0X00, 0X3F, 0X03, 0XF0, 0X3F, 0X03, 0XF0, 0X00, 0X00, 0X00, 0X0C, 0X00, 0X00, 0X00, 0XC0, 0X00,
0X00, 0X21, 0X02, 0X10, 0X21, 0X02, 0X10, 0X00, 0X00, 0X00, 0X0C, 0X00, 0X18, 0XFF, 0XE0, 0X00,
0X00, 0X21, 0X02, 0X10, 0X21, 0X02, 0X10, 0X00, 0X00, 0X00, 0X08, 0X1C, 0X1C, 0X1B, 0X00, 0X00,
0X00, 0X21, 0X02, 0X10, 0X21, 0X02, 0X10, 0X00, 0X00, 0X1F, 0XFF, 0XFE, 0X0C, 0X0E, 0X00, 0X00,
0X00, 0X21, 0X02, 0X10, 0X21, 0X02, 0X10, 0X00, 0X00, 0X00, 0X0C, 0X00, 0X00, 0X8C, 0X60, 0X00,
0X00, 0X21, 0X02, 0X10, 0X21, 0X02, 0X10, 0X00, 0X00, 0X04, 0X0C, 0X10, 0X00, 0XFF, 0XF0, 0X00,
0X00, 0X21, 0X02, 0X10, 0X21, 0X02, 0X10, 0X00, 0X00, 0X07, 0XFF, 0XF8, 0X0C, 0XCC, 0X60, 0X00,
0X00, 0X21, 0X02, 0X10, 0X21, 0X02, 0X10, 0X00, 0X00, 0X06, 0X63, 0X18, 0X7E, 0XCC, 0X60, 0X00,
0X7F, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XF8, 0X00, 0X06, 0X33, 0X98, 0X0C, 0XFF, 0XE0, 0X00,
0X7F, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XF8, 0X00, 0X06, 0X32, 0X18, 0X0C, 0XCC, 0X60, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00, 0X06, 0X05, 0XD8, 0X0C, 0XCC, 0X60, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00, 0X06, 0XFF, 0X78, 0X0C, 0XFF, 0XE0, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00, 0X06, 0X08, 0XD8, 0X0C, 0XCC, 0X60, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00, 0X07, 0XFF, 0XF8, 0X0C, 0XCC, 0X60, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00, 0X06, 0X0C, 0X18, 0X0C, 0XCF, 0XE0, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00, 0X06, 0X0C, 0X18, 0X3E, 0X80, 0X40, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00, 0X06, 0X0C, 0X18, 0X73, 0XC0, 0X00, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00, 0X06, 0X0D, 0XF0, 0X20, 0X7F, 0XF8, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00, 0X06, 0X00, 0X30, 0X00, 0X00, 0X00, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00, 0X06, 0X00, 0X18, 0X01, 0X84, 0X00, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00, 0X07, 0XFF, 0XFC, 0X01, 0XC6, 0X00, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00, 0X06, 0X00, 0X58, 0X01, 0X86, 0X30, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00, 0X07, 0XFF, 0XD8, 0X7F, 0XFF, 0XF8, 0X00,
0X60, 0X00, 0XFD, 0X1F, 0XF0, 0X7A, 0X00, 0X18, 0X00, 0X06, 0X0C, 0X18, 0X01, 0X86, 0X00, 0X00,
0X60, 0X01, 0X87, 0X13, 0X30, 0XC6, 0X00, 0X18, 0X00, 0X06, 0X0C, 0X18, 0X01, 0X86, 0X00, 0X00,
0X60, 0X03, 0X03, 0X33, 0X11, 0X83, 0X00, 0X18, 0X00, 0X06, 0X0C, 0X18, 0X00, 0X40, 0X00, 0X00,
0X60, 0X03, 0X03, 0X03, 0X01, 0X83, 0X00, 0X18, 0X00, 0X06, 0X0C, 0XD8, 0X00, 0X30, 0X00, 0X00,
0X60, 0X03, 0X80, 0X03, 0X03, 0X80, 0X00, 0X18, 0X00, 0X06, 0XFF, 0XF8, 0X03, 0X38, 0X00, 0X00,
0X60, 0X01, 0XC0, 0X03, 0X03, 0X00, 0X00, 0X18, 0X00, 0X06, 0X0F, 0X18, 0X0B, 0X98, 0X80, 0X00,
0X60, 0X00, 0X78, 0X03, 0X03, 0X00, 0X00, 0X18, 0X00, 0X06, 0X0D, 0X98, 0X0B, 0X18, 0XC0, 0X00,
0X60, 0X00, 0X1E, 0X03, 0X03, 0X00, 0X00, 0X18, 0X00, 0X06, 0X0C, 0XD8, 0X1B, 0X00, 0X70, 0X00,
0X60, 0X00, 0X07, 0X03, 0X03, 0X00, 0X00, 0X18, 0X00, 0X06, 0X0C, 0X18, 0X1B, 0X01, 0X30, 0X00,
0X60, 0X00, 0X03, 0X03, 0X03, 0X80, 0X00, 0X18, 0X00, 0X06, 0X0C, 0XD8, 0X3B, 0X01, 0X30, 0X00,
0X60, 0X03, 0X03, 0X03, 0X03, 0X83, 0X00, 0X18, 0X00, 0X07, 0XF7, 0XB8, 0X33, 0X01, 0X80, 0X00,
0X60, 0X03, 0X03, 0X03, 0X01, 0X82, 0X00, 0X18, 0X00, 0X06, 0X00, 0X18, 0X03, 0X01, 0X80, 0X00,
0X60, 0X01, 0XC6, 0X03, 0X01, 0XC6, 0X00, 0X18, 0X00, 0X07, 0XFF, 0XF8, 0X01, 0XFF, 0X80, 0X00,
0X60, 0X01, 0X7C, 0X07, 0XC0, 0X7C, 0X00, 0X18, 0X00, 0X06, 0X00, 0X18, 0X00, 0X00, 0X00, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X21, 0X86, 0X00, 0X07, 0X00, 0X00, 0X00, 0X10,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X31, 0X86, 0X00, 0X07, 0X00, 0X03, 0XFF, 0XF8,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X65, 0X66, 0X00, 0X02, 0X00, 0X00, 0X00, 0X68,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0XC7, 0X7C, 0X00, 0X02, 0X08, 0X00, 0X00, 0XC0,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X95, 0X6C, 0X41, 0XFF, 0XFC, 0X00, 0X03, 0X80,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X19, 0X3D, 0X6F, 0XE1, 0X82, 0X0C, 0X00, 0X0E, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X3E, 0XE9, 0XA1, 0X82, 0X0C, 0X00, 0X0E, 0X00,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X60, 0X59, 0X81, 0X82, 0X0C, 0X00, 0X0C, 0X0C,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0X6F, 0XFD, 0X81, 0XFF, 0XFC, 0X1F, 0XFF, 0XFE,
0X60, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X18, 0XE0, 0X15, 0X81, 0X82, 0X0C, 0X00, 0X0C, 0X02,
0X7F, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XF8, 0XA6, 0X45, 0X81, 0X82, 0X0C, 0X00, 0X0C, 0X00,
0X7F, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XF9, 0X27, 0XC7, 0X01, 0X82, 0X0C, 0X00, 0X0C, 0X00,
0X00, 0X21, 0X02, 0X10, 0X21, 0X02, 0X10, 0X00, 0X26, 0X47, 0X01, 0XFF, 0XFC, 0X00, 0X0C, 0X00,
0X00, 0X21, 0X02, 0X10, 0X21, 0X02, 0X10, 0X00, 0X26, 0X5F, 0X01, 0X82, 0X0B, 0X00, 0X0C, 0X00,
0X00, 0X21, 0X02, 0X10, 0X21, 0X02, 0X10, 0X00, 0X26, 0X77, 0X01, 0X02, 0X03, 0X00, 0X0C, 0X00,
0X00, 0X21, 0X02, 0X10, 0X21, 0X02, 0X10, 0X00, 0X26, 0XEF, 0X80, 0X02, 0X03, 0X00, 0X0C, 0X00,
0X00, 0X21, 0X02, 0X10, 0X21, 0X02, 0X10, 0X00, 0X24, 0X59, 0XC0, 0X02, 0X03, 0X00, 0X0C, 0X00,
0X00, 0X21, 0X02, 0X10, 0X21, 0X02, 0X10, 0X00, 0X38, 0X30, 0XE0, 0X03, 0XFF, 0X80, 0X7C, 0X00,
0X00, 0X21, 0X02, 0X10, 0X21, 0X02, 0X10, 0X00, 0X38, 0XE0, 0X00, 0X00, 0X00, 0X00, 0X18, 0X00,
0X00, 0X3F, 0X03, 0XF0, 0X3F, 0X03, 0XF0, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,
};
void GPIO_init(void)
{
P0M1 = 0;
P0M0 = 0; // 设置为准双向口
P1M1 = 0;
P1M0 = 0; // 设置为准双向口
P2M1 = 0;
P2M0 = 0; // 设置为准双向口
P3M1 = 0;
P3M0 = 0; // 设置为准双向口
P4M1 = 0;
P4M0 = 0; // 设置为准双向口
P5M1 = 0;
P5M0 = 0; // 设置为准双向口
P6M1 = 0;
P6M0 = 0; // 设置为准双向口
P7M1 = 0;
P7M0 = 0; // 设置为准双向口
}
void main(void)
{
u8 is_ST7920_need_spi = 0; // 假设开始是ST7920并口通讯
// GPIO初始化
GPIO_init();
delay_ms(100); // 启动等待,等LCD讲入工作状态
while (1) {
ST7290_Init(is_ST7920_need_spi); // LCM初始化
ST7290_Clear();
ST7290_show_pic(gImage_gxw); // 显示图形
delay_ms(is_ST7920_need_spi ? 1000 : 3000); // 交替显示时, 可以根据图像显示的时长, 分出哪种显示是哪种通讯方式
ST7290_Clear();
ST7290_show_text(0, 1, uctech); // 显示字库中的中文数字
ST7290_show_text(0, 2, net); // 显示字库中的中文数字
ST7290_show_text(0, 3, mcu); // 显示字库中的中文
ST7290_show_text(0, 4, qq); // 显示字库中的中文数字
delay_ms(is_ST7920_need_spi ? 1000 : 3000); // 交替显示时, 可以分出哪种显示是哪种通讯方式
is_ST7920_need_spi = !is_ST7920_need_spi; // 下一次显示时, 换另外一种显示方式(并口通讯/串行通讯)
}
}
//========================================================================
// 函数: void delay_ms(u8 ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注:
//========================================================================
void delay_ms(u16 ms)
{
u16 i;
do {
i = MAIN_Fosc / 13000;
while (--i) ; //14T per loop
} while (--ms);
}
//******************************************
void LCD_delay(void)
{
NOP(10);
}
void ST7920_SPI_SendByte(u8 Dbyte)
{
u8 i = 0;
for (i = 0; i < 8; i++) {
ST7920_E_SCLK = 0;
Dbyte = Dbyte << 1; //左移一位
ST7920_RW_SID = CY; //移出的位给SID
ST7920_E_SCLK = 1;
ST7920_E_SCLK = 0;
}
// LCD_delay();
}
u8 ST7920_SPI_RecvByte(void)
{
u8 i, temp1, temp2;
temp1 = 0;
temp2 = 0;
for (i = 0; i < 8; i++) {
temp1 = temp1 << 1;
ST7920_E_SCLK = 0;
ST7920_E_SCLK = 1;
ST7920_E_SCLK = 0;
if (ST7920_RW_SID) {
temp1++;
}
}
for (i = 0; i < 8; i++) {
temp2 = temp2 << 1;
ST7920_E_SCLK = 0;
ST7920_E_SCLK = 1;
ST7920_E_SCLK = 0;
if (ST7920_RW_SID) {
temp2++;
}
}
return ((0xf0 & temp1) + (0x0f & temp2));
}
//读状态
u8 ST7290_ReadStatus(void)
{
u8 u8_status = 0;
if (1 == ST7920_PSB) {
ST7920_DATA_PORT = 0xFF;
ST7920_RS_CS = 0;
ST7920_RW_SID = 1;
LCD_delay();
ST7920_E_SCLK = 1;
LCD_delay();
do {
u8_status = ST7920_DATA_PORT;
} while (u8_status & ST7920_FLAG_BUSY); // 检测忙信号
ST7920_E_SCLK = 0;
} else {
ST7920_RS_CS = 1;
do {
ST7920_SPI_SendByte(0xfc); // 11111,RW(1),RS(0),0
u8_status = ST7920_SPI_RecvByte();
} while (u8_status & ST7920_FLAG_BUSY); // 检测忙信号
}
return u8_status;
}
void ST7290_Init(u8 is_spi) // LCM初始化
{
if (is_spi) {
ST7920_PSB = 0; // SPI口
ST7920_RS_CS = 1;
} else {
ST7920_PSB = 1; //并口
}
delay_ms(10);
ST7920_RESET = 0;
delay_ms(10);
ST7920_RESET = 1;
delay_ms(100);
ST7290_WriteCmd(0x30, 1); // 显示模式设置,开始要求每次检测忙信号
ST7290_WriteCmd(0x01, 1); // 显示清屏
ST7290_WriteCmd(0x06, 1); // 显示光标移动设置
ST7290_WriteCmd(0x0C, 1); // 显示开及光标设置
}
void ST7290_Clear(void) // 清屏
{
ST7290_WriteCmd(0x01, 1); //显示清屏
ST7290_WriteCmd(0x34, 1); // 显示光标移动设置
ST7290_WriteCmd(0x30, 1); // 显示开及光标设置
}
//按指定位置显示一串字符
void ST7290_show_text(u8 X, u8 Y, u8 code* DData)
{
u8 ListLength = 0;
u8 X2 = X;
if (Y < 1) {
Y = 1;
}
if (Y > 4) {
Y = 4;
}
X &= 0x0F; //限制X不能大于16,Y在1-4之内
switch (Y) {
case 1:
X2 |= 0X80;
break; //根据行数来选择相应地址
case 2:
X2 |= 0X90;
break;
case 3:
X2 |= 0X88;
break;
case 4:
X2 |= 0X98;
break;
}
ST7290_WriteCmd(X2, 1); //发送地址码
while (DData[ListLength] >= 0x20) { //若到达字串尾则退出
if (X <= 0x0F) { //X坐标应小于0xF
ST7290_WriteData(DData[ListLength], 1); //
ListLength++;
X++;
}
}
}
void ST7290_show_pic(u8 code* DData)
{
u8 x, y, i;
unsigned int tmp = 0;
for (i = 0; i < 9;) { // 分两屏,上半屏和下半屏,因为起始地址不同,需要分开
for (x = 0; x < 32; x++) { // 32行
ST7290_WriteCmd(0x34, 1);
ST7290_WriteCmd((0x80 + x), 1); // 列地址
ST7290_WriteCmd((0x80 + i), 1); // 行地址,下半屏,即第三行地址0X88
ST7290_WriteCmd(0x30, 1);
for (y = 0; y < 16; y++) {
ST7290_WriteData(DData[tmp + y], 1); // 读取数据写入LCD
}
tmp += 16;
}
i += 8;
}
ST7290_WriteCmd(0x36, 1); // 扩充功能设定
ST7290_WriteCmd(0x30, 1);
}
// 写数据
void ST7290_WriteData(u8 WDLCD, BuysC)
{
if (BuysC) {
ST7290_ReadStatus(); //根据需要检测忙
}
if (1 == ST7920_PSB) {
// ST7920并口通讯
ST7920_RS_CS = 1;
ST7920_RW_SID = 0;
ST7920_DATA_PORT = WDLCD;
LCD_delay();
ST7920_E_SCLK = 1;
LCD_delay();
ST7920_E_SCLK = 0;
} else {
// ST7920串口通讯
ST7920_SPI_SendByte(0xfa); //11111,RW(0),RS(1),0
ST7920_SPI_SendByte(0xf0 & WDLCD); //高四位
ST7920_SPI_SendByte(0xf0 & (WDLCD << 4)); //低四位(先执行<<)
}
}
//写指令
void ST7290_WriteCmd(u8 WCLCD, BuysC) //BuysC为0时忽略忙检测
{
if (BuysC) {
ST7290_ReadStatus(); //根据需要检测忙
}
if (1 == ST7920_PSB) {
ST7920_RS_CS = 0;
ST7920_RW_SID = 0;
ST7920_DATA_PORT = WCLCD;
LCD_delay();
ST7920_E_SCLK = 1;
LCD_delay();
ST7920_E_SCLK = 0;
} else {
ST7920_RS_CS = 1;
ST7920_SPI_SendByte(0xf8); //11111,RW(0),RS(0),0
ST7920_SPI_SendByte(0xf0 & WCLCD); //高四位
ST7920_SPI_SendByte(0xf0 & (WCLCD << 4)); //低四位(先执行<<)
delay_ms(1); // ST7920的串口方式比并口方式反应慢点, 需要延时, 否则第一行花屏. 必须加延时!!!
}
}
原理图
官方板子这么接ST7920-12864时, 既可以用并口通讯方式, 也可以用串口通讯方式.
如果是自己实际工程用ST7920-12864, 还是用串口方式好些, 省8个连续的数据IO. 实际的IO可以挑选零散闲置的GPIO来代替.