hd44780_i2c_lcd.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*
  2. * hd44780_i2c_lcd.c
  3. *
  4. * Copyright 2022 dh33ex <dh33ex@riseup.net>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  19. * MA 02110-1301, USA or see <http://www.gnu.org/licenses/>.
  20. *
  21. *
  22. */
  23. #ifndef __msp430_h_
  24. #include <msp430.h>
  25. #endif
  26. #include "hd44780_i2c_lcd.h"
  27. /*
  28. * P0 - RS
  29. * P1 - R/W
  30. * P2 - E
  31. * P3 - LIGHT
  32. * P4 - DB4
  33. * P5 - DB5
  34. * P6 - DB6
  35. * P7 - DB7
  36. */
  37. #define PCF8574_RS 0x01
  38. #define PCF8574_RW 0x02
  39. #define PCF8574_E 0x04
  40. #define PCF8574_LIGHT 0x08
  41. #define PCF8574_DB4 0x10
  42. #define PCF8574_DB5 0x20
  43. #define PCF8574_DB6 0x40
  44. #define PCF8574_DB7 0x80
  45. #define HD44780_CLEARDISPLAY 0x01
  46. #define HD44780_RETURNHOME 0x02
  47. #define HD44780_ENTRYMODESET 0x04
  48. #define HD44780_ID 0x02
  49. #define HD44780_S 0x01
  50. #define HD44780_DISPLAYCONTROL 0x08
  51. #define HD44780_D 0x04
  52. #define HD44780_C 0x02
  53. #define HD44780_B 0x01
  54. #define HD44780_SHIFTSETUP 0x10
  55. #define HD44780_SC 0x08
  56. #define HD44780_RL 0x04
  57. #define HD44780_FUNCTIONSET 0x20
  58. #define HD44780_F 0x04
  59. #define HD44780_N 0x08
  60. #define HD44780_DL 0x10
  61. #define HD44780_DDRAM_ADDRESS 0x80
  62. #define HD44780_CGRAM_ADDRESS 0x40
  63. #define HD44780_DATA 1
  64. #define HD44780_INSTRUCTION 0
  65. char i2c_buffer;
  66. void PCF8574_send(unsigned char byte);
  67. void HD44780_send(HD44780 *disp, unsigned char type, unsigned char data);
  68. void PCF8574_send(unsigned char byte) {
  69. while (UCB0STAT & UCBUSY); /* wait until I2C is free */
  70. i2c_buffer = byte;
  71. IFG2 &= ~UCB0TXIFG; /* clear transmit interrupt flag */
  72. UCB0CTL1 |= UCTXSTT; /* send start message manually */
  73. UCB0TXBUF = i2c_buffer; /* load TX buffer */
  74. while (!(IFG2 & UCB0TXIFG));
  75. UCB0CTL1 |= UCTXSTP; /* send stop message manually */
  76. while (UCB0CTL1 & UCTXSTP); /* wait until stop message sent */
  77. __delay_cycles(1500);
  78. }
  79. void HD44780_send(HD44780 *disp, unsigned char type, unsigned char data) {
  80. PCF8574_send((data & 0xF0) | (type ? PCF8574_RS : 0) | PCF8574_E);
  81. PCF8574_send((data & 0xF0) | (type ? PCF8574_RS : 0));
  82. PCF8574_send((data << 4) | (type ? PCF8574_RS : 0) | PCF8574_E);
  83. PCF8574_send((data << 4) | (type ? PCF8574_RS : 0) | PCF8574_LIGHT * disp->light);
  84. }
  85. void LCD_init(HD44780 *disp) {
  86. /* setup B0 for I2C */
  87. UCB0CTL1 |= UCSWRST; /* put B0 in SW RST */
  88. UCB0CTL1 |= UCSSEL_2; /* choose SMCLK */
  89. UCB0BR0 = 10; /* set presalar to 10 */
  90. UCB0BR1 = 0;
  91. UCB0CTL0 |= UCMODE_3; /* put into I2C mode */
  92. UCB0CTL0 |= UCMST; /* set as master */
  93. UCB0I2CSA = disp->address; /* set slave address */
  94. /* setup ports */
  95. P1SEL |= BIT7; /* P1.7 = SDA */
  96. P1SEL2 |= BIT7;
  97. P1SEL |= BIT6; /* P1.6 = SCL */
  98. P1SEL2 |= BIT6;
  99. UCB0CTL1 |= UCTR; /* set transmit mode */
  100. UCB0CTL1 &= ~UCSWRST; /* take B0 out of SW RST */
  101. /* init display */
  102. __delay_cycles(40000); /* delay 40 ms */
  103. PCF8574_send(PCF8574_DB5 | PCF8574_DB4 | PCF8574_E);
  104. PCF8574_send(PCF8574_DB5 | PCF8574_DB4);
  105. __delay_cycles(4100); /* delay 4.1 ms */
  106. PCF8574_send(PCF8574_DB5 | PCF8574_DB4 | PCF8574_E);
  107. PCF8574_send(PCF8574_DB5 | PCF8574_DB4);
  108. __delay_cycles(1000); /* delay 1 us */
  109. PCF8574_send(PCF8574_DB5 | PCF8574_DB4 | PCF8574_E);
  110. PCF8574_send(PCF8574_DB5 | PCF8574_DB4);
  111. PCF8574_send(PCF8574_DB5 | PCF8574_E);
  112. PCF8574_send(PCF8574_DB5);
  113. HD44780_send(disp, HD44780_INSTRUCTION, HD44780_FUNCTIONSET | (disp->rows == 1 ? 0 : HD44780_N));
  114. HD44780_send(disp, HD44780_INSTRUCTION, HD44780_DISPLAYCONTROL | HD44780_D | (disp->cursor == HD44780_NO_CURSOR ? 0 : (disp->cursor == HD44780_BLINK_CURSOR ? HD44780_B : HD44780_C)));
  115. HD44780_send(disp, HD44780_INSTRUCTION, HD44780_CLEARDISPLAY);
  116. HD44780_send(disp, HD44780_INSTRUCTION, HD44780_ENTRYMODESET | HD44780_ID);
  117. }
  118. void LCD_clear(HD44780 *disp) {
  119. HD44780_send(disp, HD44780_INSTRUCTION, HD44780_CLEARDISPLAY);
  120. }
  121. void LCD_backlight(HD44780 *disp, unsigned char state) {
  122. disp->light = state;
  123. PCF8574_send(PCF8574_LIGHT*disp->light);
  124. }
  125. void LCD_write(HD44780 *disp, char *string) {
  126. PCF8574_send(0x0);
  127. while (*string != '\0') {
  128. HD44780_send(disp, HD44780_DATA, *(string++));
  129. }
  130. __delay_cycles(10);
  131. PCF8574_send(disp->light * PCF8574_LIGHT);
  132. }
  133. void LCD_set_address(HD44780 *disp, unsigned char x, unsigned char y) {
  134. unsigned char x_start[] = {0x00, 0x40, disp->columns, 0x40+disp->columns};
  135. HD44780_send(disp, HD44780_INSTRUCTION, HD44780_DDRAM_ADDRESS | (x_start[y] + x));
  136. }
  137. #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
  138. #pragma vector = USCIAB0TX_VECTOR
  139. __interrupt void USCIAB0TX_I2C_ISR(void) {
  140. #elif defined(__GNUC__)
  141. void __attribute__ ((interrupt(USCIAB0TX_VECTOR))) USCIAB0TX_I2C_ISR (void) {
  142. #else
  143. #error Compiler not supported!
  144. #endif
  145. UCB0TXBUF = i2c_buffer; /* load TX buffer */
  146. while (!(IFG2 & UCB0TXIFG));
  147. IE2 &= ~UCB0TXIE; /* disable interrupts */
  148. IFG2 &= ~UCB0TXIFG; /* clear USCI_B0 TX int flag */
  149. __bic_SR_register_on_exit(LPM0_bits); /* exit LPM0 */
  150. }