<前言>
繼上一篇測試後,我們開始我們的開發,本開發設計基於MTK的Tutorial加以修改而成,但因為手邊並沒有Seeed所提供的LCD1602,所以必須自己根據範例原始碼來進行修改和移植,本篇著重在LCD1602-I2C介面的驅動修改和移植,下篇為驗證和增加整點報時
<準備>
1. 7687HDK開發板
2. MicroUSB傳輸線,有附
<實作>
1. 雖然Tutorial有提供完整的原始碼,但是為GCC環境編譯方式,而我是採用MDK- ARM,因此我們需要一個類似的範例來作修改,剛好在範例中找到SNTP的相關範例,要注意的是,所有APP範例中都是基於FreeRTOS的實時系統,這裡假設小伙伴們已經有些概念
- 4.1.0projectmt7687_hdkappssntp_client
复制代码
2. 打開MDK-ARM,並下載GCC範例的原始碼,https://github.com/MediaTek-Labs/linkit-7687-tutorial-digital-clock-part1,然後解壓縮,取出我們要的LCD驅動部分進行修改,檔案為 lcd.c和 lcd.h
Fig.1 lcd.c檔所在位置,放置到 4.1.0projectmt7687_hdkappssntp_clientsrc
Fig.2 lcd.h檔所在位置,放置到 4.1.0projectmt7687_hdkappssntp_clientinc
3. 在專案工程中增加一個Group,並命名為lcd,並加入剛剛獲取的原始碼檔lcd.c
Fig.3 增加lcd.c原始碼檔
4. 開始修改原始碼,我的LCD1602-I2C模塊是Funduino出品,I2C晶片為PCF8574T,LCD晶片為HD44780,和官方所使用I2C晶片AIP31068L不同,因此我們必須修改成舊有的LCD1602-I2C驅動又能和7687HDK正確交互,所參考的舊版Arduino的Github原始碼出處
https://github.com/marcoschwartz/LiquidCrystal_I2C
5. 修改完成的lcd.c為以下
- /* Kernel includes. */
- #include "FreeRTOS.h"
- #include "lcd.h"
- static uint8_t _displayfunction;
- static uint8_t _displaycontrol;
- static uint8_t _displaymode;
- static uint8_t _backlightval;
- static uint8_t _initialized;
- static uint8_t _numlines,_currline;
- static void (*_write_func)(uint8_t addr, uint8_t* data, uint8_t dataLen);
- static void _i2c_send_byte(unsigned char data)
- {
- uint8_t d[1];
- d[0] = data | _backlightval;
- _write_func(LCD_ADDRESS, d, 1);
- }
- static void _i2c_send_byte2(unsigned char data1, unsigned char data2)
- {
- uint8_t d[2];
- d[0] = data1;
- d[1] = data2;
- _write_func(LCD_ADDRESS, d, 2);
- }
- void rgblcd_registerFunc(void (*i2cWrite)(uint8_t addr, uint8_t* data, uint8_t dataLen))
- {
- _write_func = i2cWrite;
- }
- void rgblcd_begin(uint8_t cols, uint8_t lines)
- {
- uint8_t dotsize = LCD_5x8DOTS;
- _backlightval = LCD_NOBACKLIGHT;
-
- _displayfunction=LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
-
- if (lines > 1) {
- _displayfunction |= LCD_2LINE;
- }
- _numlines = lines;
- _currline = 0;
- // for some 1 line displays you can select a 10 pixel high font
- if ((dotsize != 0) && (lines == 1)) {
- _displayfunction |= LCD_5x10DOTS;
- }
- // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
- // according to datasheet, we need at least 40ms after power rises above 2.7V
- // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
- vTaskDelay(US2TICK(50000));
- // this is according to the hitachi HD44780 datasheet
- // page 46 figure 24
-
- // Send function set command sequence
- // we start in 8bit mode, try to set 4 bit mode
- write4bits(0x03 << 4);
- vTaskDelay(US2TICK(4500)); // wait min 4.1ms
-
- // second try
- write4bits(0x03 << 4);
- vTaskDelay(US2TICK(150)); // wait min 100us
-
- // third go!
- write4bits(0x03 << 4);
-
-
- // finally, set to 4-bit interface
- write4bits(0x02 << 4);
- //set # lines, font size, etc.
- rgblcd_command(LCD_FUNCTIONSET | _displayfunction);
- // turn the display on with no cursor or blinking default
- _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
- rgblcd_display();
- // clear it off
- rgblcd_clear();
- // Initialize to default text direction (for romance languages)
- _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
- // set the entry mode
- rgblcd_command(LCD_ENTRYMODESET | _displaymode);
- }
- /********** high level commands, for the user! */
- void rgblcd_clear()
- {
- rgblcd_command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
- vTaskDelay(US2TICK(2000)); // this command takes a long time!
- }
- void rgblcd_home()
- {
- rgblcd_command(LCD_RETURNHOME); // set cursor position to zero
- vTaskDelay(US2TICK(2000)); // this command takes a long time!
- }
- void rgblcd_setCursor(uint8_t col, uint8_t row)
- {
- int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
- if ( row > _numlines ) {
- row = _numlines-1; // we count rows starting w/0
- }
- rgblcd_command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
- }
- // Turn the display on/off (quickly)
- void rgblcd_noDisplay()
- {
- _displaycontrol &= ~LCD_DISPLAYON;
- rgblcd_command(LCD_DISPLAYCONTROL | _displaycontrol);
- }
- void rgblcd_display() {
- _displaycontrol |= LCD_DISPLAYON;
- rgblcd_command(LCD_DISPLAYCONTROL | _displaycontrol);
- }
- // Turns the underline cursor on/off
- void rgblcd_noCursor()
- {
- _displaycontrol &= ~LCD_CURSORON;
- rgblcd_command(LCD_DISPLAYCONTROL | _displaycontrol);
- }
- void rgblcd_cursor() {
- _displaycontrol |= LCD_CURSORON;
- rgblcd_command(LCD_DISPLAYCONTROL | _displaycontrol);
- }
- // Turn on and off the blinking cursor
- void rgblcd_noBlink()
- {
- _displaycontrol &= ~LCD_BLINKON;
- rgblcd_command(LCD_DISPLAYCONTROL | _displaycontrol);
- }
- void rgblcd_blink()
- {
- _displaycontrol |= LCD_BLINKON;
- rgblcd_command(LCD_DISPLAYCONTROL | _displaycontrol);
- }
- // These commands scroll the display without changing the RAM
- void rgblcd_scrollDisplayLeft(void)
- {
- rgblcd_command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
- }
- void rgblcd_scrollDisplayRight(void)
- {
- rgblcd_command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
- }
- // This is for text that flows Left to Right
- void rgblcd_leftToRight(void)
- {
- _displaymode |= LCD_ENTRYLEFT;
- rgblcd_command(LCD_ENTRYMODESET | _displaymode);
- }
- // This is for text that flows Right to Left
- void rgblcd_rightToLeft(void)
- {
- _displaymode &= ~LCD_ENTRYLEFT;
- rgblcd_command(LCD_ENTRYMODESET | _displaymode);
- }
- // This will 'right justify' text from the cursor
- void rgblcd_autoscroll(void)
- {
- _displaymode |= LCD_ENTRYSHIFTINCREMENT;
- rgblcd_command(LCD_ENTRYMODESET | _displaymode);
- }
- // This will 'left justify' text from the cursor
- void rgblcd_noAutoscroll(void)
- {
- _displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
- rgblcd_command(LCD_ENTRYMODESET | _displaymode);
- }
- // Turn the (optional) backlight off/on
- void rgblcd_noBacklight(void) {
- _backlightval=LCD_NOBACKLIGHT;
- _i2c_send_byte(0);
- }
- void rgblcd_backlight(void) {
- _backlightval=LCD_BACKLIGHT;
- _i2c_send_byte(0);
- }
- /*********** mid level commands, for sending data/cmds */
- // send command
- void rgblcd_command(uint8_t value)
- {
- uint8_t highnib=value&0xf0;
- uint8_t lownib=(value<<4)&0xf0;
- write4bits(highnib&~Rs);
- write4bits(lownib&~Rs);
- }
- // send data
- void rgblcd_write(uint8_t value)
- {
- uint8_t highnib=value&0xf0;
- uint8_t lownib=(value<<4)&0xf0;
- write4bits(highnib|Rs);
- write4bits(lownib|Rs);
- }
- void rgblcd_write_str(const char *value)
- {
- while(*value)
- {
- uint8_t highnib=(*value)&0xf0;
- uint8_t lownib=((*value)<<4)&0xf0;
- write4bits(highnib|Rs);
- write4bits(lownib|Rs);
- value++;
- }
- }
- void write4bits(uint8_t value) {
- _i2c_send_byte(value|En);
- vTaskDelay(US2TICK(1));
- _i2c_send_byte((value)&~En);
- vTaskDelay(US2TICK(50));
- }
复制代码
其中初始化LCD為4Bit輸入的指令序列,如HD44780 datasheet所表示
Fig.4 4Bit輸入模式初始化序列
Fig.5 各指令集修改的參考依據
Fig.6 各指令集修改的參考依據
並使用FreeRTOS的延時函式,和SDK所提供HAL I2C的庫函式,整合在lcd.c中,其他程式碼涵義註解已經很清楚表達,然後我也將MTK原來的原始碼作調整,將define搬移至標頭檔,因此lcd.h如下
- #include
- #include
- #include
- // Device I2C Arress
- #define LCD_ADDRESS (0x27)
- // commands
- #define LCD_CLEARDISPLAY 0x01
- #define LCD_RETURNHOME 0x02
- #define LCD_ENTRYMODESET 0x04
- #define LCD_DISPLAYCONTROL 0x08
- #define LCD_CURSORSHIFT 0x10
- #define LCD_FUNCTIONSET 0x20
- #define LCD_SETCGRAMADDR 0x40
- #define LCD_SETDDRAMADDR 0x80
- // flags for display entry mode
- #define LCD_ENTRYRIGHT 0x00
- #define LCD_ENTRYLEFT 0x02
- #define LCD_ENTRYSHIFTINCREMENT 0x01
- #define LCD_ENTRYSHIFTDECREMENT 0x00
- // flags for display on/off control
- #define LCD_DISPLAYON 0x04
- #define LCD_DISPLAYOFF 0x00
- #define LCD_CURSORON 0x02
- #define LCD_CURSOROFF 0x00
- #define LCD_BLINKON 0x01
- #define LCD_BLINKOFF 0x00
- // flags for display/cursor shift
- #define LCD_DISPLAYMOVE 0x08
- #define LCD_CURSORMOVE 0x00
- #define LCD_MOVERIGHT 0x04
- #define LCD_MOVELEFT 0x00
- // flags for function set
- #define LCD_8BITMODE 0x10
- #define LCD_4BITMODE 0x00
- #define LCD_2LINE 0x08
- #define LCD_1LINE 0x00
- #define LCD_5x10DOTS 0x04
- #define LCD_5x8DOTS 0x00
- // flags for backlight control
- #define LCD_BACKLIGHT 0x08
- #define LCD_NOBACKLIGHT 0x00
- #define En 0x04 // Enable bit
- #define Rw 0x02 // Read/Write bit
- #define Rs 0x01 // Register select bit
- #define US2TICK(us) (us/(1000*portTICK_RATE_MS))
- #define MS2TICK(ms) (ms/(portTICK_RATE_MS))
- void rgblcd_registerFunc(void (*i2cWrite)(uint8_t addr, uint8_t* data, uint8_t dataLen));
- void rgblcd_begin(uint8_t cols, uint8_t lines);
- void rgblcd_clear(void);
- void rgblcd_home(void);
- void rgblcd_setCursor(uint8_t col, uint8_t row);
- void rgblcd_noDisplay(void);
- void rgblcd_display(void);
- void rgblcd_noCursor(void);
- void rgblcd_cursor(void);
- void rgblcd_noBlink(void);
- void rgblcd_blink(void);
- void rgblcd_scrollDisplayLeft(void);
- void rgblcd_scrollDisplayRight(void);
- void rgblcd_leftToRight(void);
- void rgblcd_rightToLeft(void);
- void rgblcd_autoscroll(void);
- void rgblcd_noAutoscroll(void);
- void rgblcd_command(uint8_t value);
- void rgblcd_write(uint8_t value);
- void rgblcd_write_str(const char *value);
- void write4bits(uint8_t value);
- void rgblcd_noBacklight(void);
- void rgblcd_backlight(void);
复制代码
以上就修改完成了,可以開始進行編譯
6. 在這裡還沒有和main進行交互,所以這裡只是修改成舊版本的PCF8574的功能,並編譯成功
Fig.7 編譯成功
小結:
本篇主要說明I2C晶片組的不同而進行LCD1602的驅動修改,並能相容7687的HDK的HAL I2C函式庫,使用硬I2C進行通訊,下篇將說明如何整到main並增加整點鳴叫功能,需要對FreeRTOS有些基礎,可參考官網http://www.freertos.org/
0
|
|
|
|