首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >向HD44780控制的液晶显示器发送指令

向HD44780控制的液晶显示器发送指令
EN

Code Review用户
提问于 2017-04-10 16:20:02
回答 1查看 306关注 0票数 6

我目前的嵌入式项目使用的是由HD44780标准控制器控制的16x2LCD。我的PIC18通过Adafruit串行背包(示意图链接)与液晶显示器通话。我选择了SPI接口。

HD44780通过对8个数据引脚(DB0-7)、读/写引脚(R/W)、寄存器选择引脚(RS)和启用引脚(E)的各种指令写入来控制。链接到指令集

指令由指示特定设置的位组成.配置参数缺乏一个更好的术语。

一切都如期而至,但我对我的设计不确定。为了最好地组织代码以提高可读性和灵活性,我尝试遵循以下方法:

  • 通过头文件中的# HD44780指令分配每个配置参数
  • 为每条指令构建char类型数组,并使用适当的配置参数加载它。
  • 通过指针传递指令数组并使用shift操作按照串行背包所期望的顺序构造SPI输出来执行指令。

这一切都很好,但是,我觉得将指令存储为数组并不是最好的方法。我希望你能就你如何处理这一问题提出任何意见,以便更加明确和有效。我的头文件和.c文件在下面,main.c不包括,但通过指令别名调用LCD_send。

头文件

代码语言:javascript
复制
/* 
 * File:   LCD_SPI_16x2.h
 * Author: rbs
 * Comments:
 * Revision history: 
 */

/*Hardware configuration:
 *
 *  Adafruit LCD serial backpack bit configuration:
 *  [DB4 | DB5 | DB6 | DB7 | E | RS | RW | LITE]
 *
 *  HD44780 instruction set bit configuration (4-bit mode):
 *  [RS | RW | DB7 | DB6 | DB5 | DB4]
 * 
 *  HD44780 instruction set bit configuration (8-bit mode):
 *  [RS | RW | DB7 | DB6 | DB5 | DB4 | DB3 | DB2 | DB1 | DB0]
 * 
 *  PIC18 MSSP1 SPI peripheral:
 *  LSB first, clock = FOSC/4, SCK idle = low, TX on SCK low -> high, SDI not used
 */

// This is a guard condition so that contents of this file are not included
// more than once.  
#ifndef LCD_SPI_16X2_V2_H
#define LCD_SPI_16X2_V2_H

#include <xc.h> // include processor files - each processor file is guarded. 

//function prototypes
//void LCD_init(void);
void LCD_send(char *cmd);
void LCD_spi_out(char data);
//void LCD_send_string(const char * str);
//void LCD_set_cursr(int row, int col);

#define _E 0x08         //alias for HD44780 ENABLE bit

//HD44780 LCD parameters
#define _BL  1          //1-> backlight on       0-> backlight off

#define _ID  1          // 1-> increment         0-> decrement
#define _S   0          // 1-> display shift     0-> no shift
#define _D   0          // 1-> display on        0-> display off
#define _C   0          // 1-> cursor on         0-> cursor off
#define _B   0          // 1-> cursor blinks     0-> cursor does not blink
#define _SC  0          // 1-> shift display     0-> shift cursor
#define _RL  0          // 1-> shift to the left 0-> shift to the right
#define _N   1          // 1-> 2 lines           0-> 1 line
#define _F   0          // 1-> 5x10 dot font     0-> 5x8 dot font
#define _DL8 1          // 8-bit mode        
#define _DL4 0          // 4-bit mode

//HD44780 LCD instruction aliases
#define _Clear         LCD_send(Clear_display)
#define _Home          LCD_send(Home)
#define _Entry_mode    LCD_send(Entry_mode)
#define _Display_onOff LCD_send(Display_onOff))
#define _Cursor_shift  LCD_send(Cursor_shift)
#define _Function8     LCD_send(Function_set_8bit)
#define _Function4     LCD_send(Function_set_4bit)

//HD44780 LCD instruction set, see format note above
char Clear_display[10]      = {0,0,0,0,0,0,0,0,0,1};
char Home[10]               = {0,0,0,0,0,0,0,0,1,0};
char Entry_mode[10]         = {0,0,0,0,0,0,0,1,_ID,_S};
char Display_onOff[10]      = {0,0,0,0,0,0,1,_D,_C,_B};
char Cursor_shift[10]       = {0,0,0,0,0,1,_SC,_RL,0,0};
char Function_set_8bit[10]  = {0,0,0,0,1,_DL8,_N,_F,0,0};
char Function_set_4bit[10]  = {0,0,0,0,1,_DL4,_N,_F,0,0};
char Cursor_pos[10]         = {0,0,1,0,0,0,0,0,0,0};

#endif  /* LCD_SPI_16X2_V2_H */

.C文件

代码语言:javascript
复制
/*
 * File:   LCD_SPI_16x2.c
 * Author: rbs
 *
 * Created on April 4, 2017, 10:00 PM
 */


#include <xc.h>
#include "system_initialize.h"
#include "LCD_SPI_16x2_v2.h"


void LCD_init(){
    //not completed yet
}

void LCD_send(char *cmd){
 /* Adafruit LCD serial backpack bit configuration:
  *  UPPER:
  *  [DB4 | DB5 | DB6 | DB7 | E | RS | RW | LITE]
  *  LOWER:
  *  [DB0 | DB1 | DB2 | DB3 | E | RS | RW | LITE]
  *  HD44780 incoming instruction configuration:
  *  [RS | RW | DB7 | DB6 | DB5 | DB4 | DB3 | DB2 | DB1 | DB0]
  */
    char Upper = 0x00;
    char Lower = 0x00;

    Upper |= (*(cmd))<<2;      //set RS bit
    Upper |= (*(cmd+1))<<1;    //set RW bit
    Upper |= (*(cmd+5))<<7;    //set data bits for upper 4bits of command 
    Upper |= (*(cmd+4))<<6;
    Upper |= (*(cmd+3))<<5;
    Upper |= (*(cmd+2))<<4;
    Upper |= _BL;              //set back light bit

    Lower |= (*(cmd))<<2;      //set RS bit
    Lower |= (*(cmd+1))<<1;    //set RW bit
    Lower |= (*(cmd+9))<<7;    //set data bits for lower 4bits of command
    Lower |= (*(cmd+8))<<6;
    Lower |= (*(cmd+7))<<5;
    Lower |= (*(cmd+6))<<4;
    Lower |= _BL;              //set back light bit

    LCD_spi_out(Upper);
    LCD_spi_out(Lower);
}

void LCD_spi_out(char data){
    _CS = 0;                   //chip select = 0
    SSP1BUF = (data|_E);       //send out data with E pin high
    __delay_ms(2);
    _CS = 1;                   //clock data out of LCD backpack shift register
    __delay_ms(2);             //delay for HD44780 to process

     _CS = 0;                  //chip select = 0
    SSP1BUF = data;            //send out data with E pin low to set HD44780
    __delay_ms(2);
    _CS = 1;                   //clock data out of LCD backpack shift register
    __delay_ms(2);
}
EN

回答 1

Code Review用户

发布于 2017-04-11 01:52:04

我看到了一些可以帮助您改进代码的东西。

不要将定义放入头文件

有一些声明,比如void LCD_spi_out(char data);,还有一些定义,它们将是函数的实际主体。头文件应该只有声明。代码对函数有适当的分离,但对于数据没有分离。来修复这样的移动线

代码语言:javascript
复制
char Clear_display[10]      = {0,0,0,0,0,0,0,0,0,1};
char Home[10]               = {0,0,0,0,0,0,0,0,1,0};

进入.c文件,然后在.h文件中如下所示:

代码语言:javascript
复制
char Clear_display[10];
char Home[10];

小心使用已签名和未签名的

您的函数使用char *char作为参数,但实际上它的实现取决于char是签名还是无符号。我建议使用特定的uint8_t类型(来自<stdint.h>)。

使用更有效的存储

使用10字节来存储10位并不是很有效。相反,我建议以比特的形式存储东西。特别是,我建议将8位命令中的每一条都存储为uint8_t。例如:

代码语言:javascript
复制
uint8_t Home = 0x01u;

RSRW位是操作的内在特性,根本不需要存储。也就是说,每个命令的RS位都等于0(指定“命令”而不是“数据”),而RW总是0(指定“写”而不是“读”)。

最小化工作

请注意,UpperLower的低四位是相同的,所以只计算一次就有意义了。此外,将它们定义为位掩码可能是有意义的,这样就可以通过按位或操作轻松地添加它们。

在实际的

中使用const

正如@TobySpeight在一条评论中正确指出的那样,不变的东西应该声明为const。在这段代码中,这将是数据数组和LCD_send函数的参数,因为该函数不会也不应该更改传递的数组。

考虑汇编语言

在嵌入式系统中,内存和CPU周期通常都供不应求,因此对于嵌入式系统程序员来说,使用汇编语言对代码的某些部分使用汇编语言更为常见。缺点是代码固有的可移植性较低,而且可能更难维护。与C语言相比,使用汇编语言更直接地完成位操作,但我们仍然可以在C中进行改进。一种方法可能如下所示:

代码语言:javascript
复制
void LCD_send_cmd(uint8_t cmd) {
    uint8_t hi = _BL;
    uint8_t lo = _BL;
    lo |= (cmd & 0x01) ? 0x80 : 0;
    lo |= (cmd & 0x02) ? 0x40 : 0;
    lo |= (cmd & 0x04) ? 0x20 : 0;
    lo |= (cmd & 0x08) ? 0x10 : 0;
    hi |= (cmd & 0x10) ? 0x80 : 0;
    hi |= (cmd & 0x20) ? 0x40 : 0;
    hi |= (cmd & 0x40) ? 0x20 : 0;
    hi |= (cmd & 0x80) ? 0x10 : 0;
    LCD_spi_out(hi);
    LCD_spi_out(lo);
}

或者,可能值得将位操作排除在外,这样您就可以同时发送命令和数据:

代码语言:javascript
复制
void LCD_send(uint8_t cmd, uint8_t flags) {
    uint8_t hi = flags;
    uint8_t lo = flags;
    lo |= (cmd & 0x01) ? 0x80 : 0;
    lo |= (cmd & 0x02) ? 0x40 : 0;
    lo |= (cmd & 0x04) ? 0x20 : 0;
    lo |= (cmd & 0x08) ? 0x10 : 0;
    hi |= (cmd & 0x10) ? 0x80 : 0;
    hi |= (cmd & 0x20) ? 0x40 : 0;
    hi |= (cmd & 0x40) ? 0x20 : 0;
    hi |= (cmd & 0x80) ? 0x10 : 0;
    LCD_spi_out(hi);
    LCD_spi_out(lo);
}

void LCD_send_cmd(uint8_t cmd) {
    LCD_send(cmd, _BL);
}

void LCD_send_data(uint8_t cmd) {
    LCD_send(cmd, RS | _BL);
}
票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/160332

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档