我目前的嵌入式项目使用的是由HD44780标准控制器控制的16x2LCD。我的PIC18通过Adafruit串行背包(示意图链接)与液晶显示器通话。我选择了SPI接口。
HD44780通过对8个数据引脚(DB0-7)、读/写引脚(R/W)、寄存器选择引脚(RS)和启用引脚(E)的各种指令写入来控制。链接到指令集。
指令由指示特定设置的位组成.配置参数缺乏一个更好的术语。
一切都如期而至,但我对我的设计不确定。为了最好地组织代码以提高可读性和灵活性,我尝试遵循以下方法:
这一切都很好,但是,我觉得将指令存储为数组并不是最好的方法。我希望你能就你如何处理这一问题提出任何意见,以便更加明确和有效。我的头文件和.c文件在下面,main.c不包括,但通过指令别名调用LCD_send。
头文件
/*
* 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文件
/*
* 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);
}发布于 2017-04-11 01:52:04
我看到了一些可以帮助您改进代码的东西。
有一些声明,比如void LCD_spi_out(char data);,还有一些定义,它们将是函数的实际主体。头文件应该只有声明。代码对函数有适当的分离,但对于数据没有分离。来修复这样的移动线
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文件中如下所示:
char Clear_display[10];
char Home[10];您的函数使用char *和char作为参数,但实际上它的实现取决于char是签名还是无符号。我建议使用特定的uint8_t类型(来自<stdint.h>)。
使用10字节来存储10位并不是很有效。相反,我建议以比特的形式存储东西。特别是,我建议将8位命令中的每一条都存储为uint8_t。例如:
uint8_t Home = 0x01u;RS和RW位是操作的内在特性,根本不需要存储。也就是说,每个命令的RS位都等于0(指定“命令”而不是“数据”),而RW总是0(指定“写”而不是“读”)。
请注意,Upper和Lower的低四位是相同的,所以只计算一次就有意义了。此外,将它们定义为位掩码可能是有意义的,这样就可以通过按位或操作轻松地添加它们。
中使用const
正如@TobySpeight在一条评论中正确指出的那样,不变的东西应该声明为const。在这段代码中,这将是数据数组和LCD_send函数的参数,因为该函数不会也不应该更改传递的数组。
在嵌入式系统中,内存和CPU周期通常都供不应求,因此对于嵌入式系统程序员来说,使用汇编语言对代码的某些部分使用汇编语言更为常见。缺点是代码固有的可移植性较低,而且可能更难维护。与C语言相比,使用汇编语言更直接地完成位操作,但我们仍然可以在C中进行改进。一种方法可能如下所示:
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);
}或者,可能值得将位操作排除在外,这样您就可以同时发送命令和数据:
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);
}https://codereview.stackexchange.com/questions/160332
复制相似问题