Home | Projects | Notes > MCU Peripheral Drivers > Board Support Package (BSP) (rtc_ds1307.h/.c, lcd_hd44780u.h/.c)
rtc_ds1307.h/.c, lcd_hd44780u.h/.c)
rtc_ds1307.hContains device (RTC) related information
I2C address (For this project, slave address)
Register addresses (Registers from which the date and time information can be extracted)
Data structure to handle information
Prototypes of the functions that are to be exposed to user applications
Application configurable items
xxxxxxxxxx811/*******************************************************************************2 * File     : rtc_ds1307.h3 * Brief    : APIs for the DS1307 RTC module4 * Author   : Kyungjae Lee5 * Date     : Jun 25, 20236 *7 * Note     : This code includes only the features that are necessary for my8 *            personal projects.9 ******************************************************************************/10
111213
1415
16/* Application configurable items */1718192021/* Doesn't support fast mode */22/* Using internal pull-up R */23
24/* Register addresses */2526272829303132
33/* DS1307 I2C address */34/* 1101000(2) */35
36/* Time formats */37383940
41/* Days */4243444546474849
50/* RTC date configuration structure */51typedef struct52{53    uint8_t date;54    uint8_t month;55    uint8_t year;56    uint8_t day;57} RTC_Date_TypeDef;58
59/* RTC time configuration structure */60typedef struct61{62    uint8_t seconds;63    uint8_t minutes;64    uint8_t hours;65    uint8_t timeFormat;66} RTC_Time_TypeDef;67
68
69/*******************************************************************************70 * APIs supported by the DS1307 RTC module71 * (See the function definitions for more information)72 ******************************************************************************/73
74uint8_t DS1307_Init(void);75void DS1307_SetCurrentTime(RTC_Time_TypeDef *);76void DS1307_GetCurrentTime(RTC_Time_TypeDef *);77void DS1307_SetCurrentDate(RTC_Date_TypeDef *);78void DS1307_GetCurrentDate(RTC_Date_TypeDef *);79
80
81/* RTC_DS1307_H */
rtc_ds1307.cxxxxxxxxxx3181/*******************************************************************************2 * File     : rtc_ds1307.c3 * Brief    : Implementation of APIs for the DS1307 RTC module4 * Author   : Kyungjae Lee5 * Date     : Jun 25, 20236 *7 * Note     : This code includes only the features that are necessary for my8 *            personal projects.9 ******************************************************************************/10
1112/* memset() */1314
15/* Private function prototypes */16static void DS1307_I2CPinConfig(void);17static void DS1307_I2CConfig(void);18static void DS1307_Write(uint8_t value, uint8_t regAddr);19static uint8_t DS1307_Read(uint8_t regAddr);20static uint8_t BcdToBinary(uint8_t bcd);21static uint8_t BinaryToBcd(uint8_t binary);22
23/* Global variables */24I2C_Handle_TypeDef gDS1307I2CHandle;25
26/**27 * DS1307_Init()28 * Desc.    : Initializes DS1307 RTC module29 * Param.   : None30 * Return   : 0 if setting DS1307_SEC CH bit to 0 was successful (init success),31 *            1 otherwise (init fail)32 * Note     : N/A33 */34uint8_t DS1307_Init(void)35{36    /* 1. Initialize the I2C pins */37    DS1307_I2CPinConfig();38
39    /* 2. Initialize the I2C peripheral */40    DS1307_I2CConfig();41
42    /* 3. Enable the I2C peripheral */43    I2C_PeriControl(DS1307_I2C, ENABLE);44
45    /* 4. Set Clock Halt (CH) bit to 0 to initiate time keeping46     * Note: At power on, the time keeping will not function until the CH bit47     *       becomes 0. So, to initiate the time keeping functionality the48     *       master needs to write 0 to the slave's CH bit.49     *       For data write logic, see the "I2C Data Bus" section of DS130750     *       reference manual.51     */52    DS1307_Write(0x0, DS1307_SEC);53
54    /* 5. Read back Clock Halt (CH) bit55     * Note: For data read logic, see the "I2C Data Bus" section of DS130756     *       reference manual.57     */58    uint8_t clockState = DS1307_Read(DS1307_SEC);59
60    return ((clockState >> 7) & 0x1);61}62
63/**64 * DS1307_SetCurrentTime()65 * Desc.    : Sets the DS1307 Seconds, Minutes, Hours registers according to66 *            the values configured in @rtcTime67 * Param.   : @rtcTime - pointer to the RTC Time structure which contains the68 *            values configured by the user69 * Return   : None70 * Note     : N/A71 */72void DS1307_SetCurrentTime(RTC_Time_TypeDef *rtcTime)73{74    uint8_t secs, hrs;75
76    /* Set seconds -----------------------------------------------------------*/77
78    secs = BinaryToBcd(rtcTime->seconds);79
80    /* Make sure to keep the CH bit (bit[7]) of the Seconds register */81    secs &= ~(0x1 << 7);82
83    DS1307_Write(secs, DS1307_SEC);84
85    /* Set minutes -----------------------------------------------------------*/86
87    DS1307_Write(BinaryToBcd(rtcTime->minutes), DS1307_MIN);88
89    /* Set hours -------------------------------------------------------------*/90
91    hrs = BinaryToBcd(rtcTime->hours);92
93    if (rtcTime->timeFormat == TIME_FORMAT_24HRS)94    {95        /* To use 24HRS time format, clear bit[6] of the Hours register */96        hrs &= ~(0x1 << 6);97    }98    else99    {100        /* To use 12HRS time format, set bit[6] of the Hours register */101        hrs |= (0x1 << 6);102
103        /* If PM, set bit[5] of the Hours register, if AM, clear it */104        hrs = (rtcTime->timeFormat == TIME_FORMAT_12HRS_PM) ? hrs | (0x1 << 5) : hrs & ~(0x1 << 5);105    }106
107    DS1307_Write(hrs, DS1307_HR);108} /* End of DS1307_SetCurrentTime */109
110/**111 * DS1307_GetCurrentTime()112 * Desc.    : Gets the current time information and stores it into @rtcTime113 * Param.   : @rtcTime - RTC_Time structure to store the current time info114 * Return   : None115 * Note     : N/A116 */117void DS1307_GetCurrentTime(RTC_Time_TypeDef *rtcTime)118{119    uint8_t secs, hrs;120
121    /* Get seconds -----------------------------------------------------------*/122
123    secs = DS1307_Read(DS1307_SEC);124    secs &= ~(0x1 << 7);    /* Exclude unnecessary bits */125    rtcTime->seconds = BcdToBinary(secs);126
127    /* Get minutes -----------------------------------------------------------*/128
129    rtcTime->minutes = BcdToBinary(DS1307_Read(DS1307_MIN));130
131    /* Get hours -------------------------------------------------------------*/132
133    hrs = DS1307_Read(DS1307_HR);134
135    if (hrs & (0x1 << 6))136    {137        /* 12HRS format */138        rtcTime->timeFormat = !((hrs & (0x1 << 5)) == 0);139        hrs &= ~(0x3 << 5); /* Clear bit[6] and bit[5] */140    }141    else142    {143        /* 24HRS format */144        rtcTime->timeFormat = TIME_FORMAT_24HRS;145    }146
147    rtcTime->hours = BcdToBinary(hrs);148} /* End of DS1307_GetCurrentTime */149
150/**151 * DS1307_SetCurrentDate()152 * Desc.    : Sets the current date information into @rtcDate153 * Param.   : @rtcDate - RTC_Date structure which contains the current date info154 * Return   : None155 * Note     : N/A156 */157void DS1307_SetCurrentDate(RTC_Date_TypeDef *rtcDate)158{159    DS1307_Write(BinaryToBcd(rtcDate->date), DS1307_DATE);160    DS1307_Write(BinaryToBcd(rtcDate->month), DS1307_MONTH);161    DS1307_Write(BinaryToBcd(rtcDate->year), DS1307_YEAR);162    DS1307_Write(BinaryToBcd(rtcDate->day), DS1307_DAY);163} /* End of DS1307_SetCurrentDate */164
165/**166 * DS1307_GetCurrentDate()167 * Desc.    : Gets the current date information and stores it into @rtcDate168 * Param.   : @rtcDate - RTC_Date structure to store the current date info169 * Return   : None170 * Note     : N/A171 */172void DS1307_GetCurrentDate(RTC_Date_TypeDef *rtcDate)173{174    rtcDate->day = BcdToBinary(DS1307_Read(DS1307_DAY));175    rtcDate->date = BcdToBinary(DS1307_Read(DS1307_DATE));176    rtcDate->month = BcdToBinary(DS1307_Read(DS1307_MONTH));177    rtcDate->year = BcdToBinary(DS1307_Read(DS1307_YEAR));178} /* End of DS1307_GetCurrentDate */179
180
181/*******************************************************************************182 * Private functions183 ******************************************************************************/184
185/**186 * DS1307_I2CPinConfig()187 * Desc.    : Configures the GPIO pins to be used for I2C communication188 * Param.   : None189 * Return   : None190 * Note     : N/A191 */192static void DS1307_I2CPinConfig(void)193{194    GPIO_Handle_TypeDef i2cSda, i2cScl;195
196    /* Zero-out all the fields in the structures (Very important! i2cSda, i2cScl197     * are local variables whose members may be filled with garbage values before198     * initialization. These garbage values may set (corrupt) the bit fields that199     * you did not touch assuming that they will be 0 by default. Do NOT make this200     * mistake!201     */202    memset(&i2cSda, 0, sizeof(i2cSda));203    memset(&i2cScl, 0, sizeof(i2cScl));204
205    /*206     * I2C1_SCL: PB6207     * I2C1_SDA: PB7208     */209
210    i2cSda.pGPIOx = DS1307_I2C_GPIO_PORT;211    i2cSda.GPIO_PinConfig.GPIO_PinAltFcnMode = 4;212    i2cSda.GPIO_PinConfig.GPIO_PinMode = GPIO_PIN_MODE_ALTFCN;213    i2cSda.GPIO_PinConfig.GPIO_PinNumber = DS1307_I2C_PIN_SDA;214    i2cSda.GPIO_PinConfig.GPIO_PinOutType= GPIO_PIN_OUT_TYPE_OD;215    i2cSda.GPIO_PinConfig.GPIO_PinPuPdControl = DS1307_I2C_PUPD;216    i2cSda.GPIO_PinConfig.GPIO_PinSpeed = GPIO_PIN_OUT_SPEED_HIGH;217
218    GPIO_Init(&i2cSda);219
220    i2cScl.pGPIOx = DS1307_I2C_GPIO_PORT;221    i2cScl.GPIO_PinConfig.GPIO_PinAltFcnMode = 4;222    i2cScl.GPIO_PinConfig.GPIO_PinMode = GPIO_PIN_MODE_ALTFCN;223    i2cScl.GPIO_PinConfig.GPIO_PinNumber = DS1307_I2C_PIN_SCL;224    i2cScl.GPIO_PinConfig.GPIO_PinOutType= GPIO_PIN_OUT_TYPE_OD;225    i2cScl.GPIO_PinConfig.GPIO_PinPuPdControl = DS1307_I2C_PUPD;226    i2cScl.GPIO_PinConfig.GPIO_PinSpeed = GPIO_PIN_OUT_SPEED_HIGH;227
228    GPIO_Init(&i2cScl);229} /* End of DS1307_I2CPinConfig */230
231/**232 * DS1307_I2CConfig()233 * Desc.    : Configures and initializes DS1307 I2C peripheral234 * Param.   : None235 * Return   : None236 * Note     : N/A237 */238static void DS1307_I2CConfig(void)239{240    gDS1307I2CHandle.pI2Cx = DS1307_I2C;241    gDS1307I2CHandle.I2C_Config.I2C_ACKEnable = I2C_ACK_ENABLE;242    gDS1307I2CHandle.I2C_Config.I2C_SCLSpeed = DS1307_I2C_SPEED;243    I2C_Init(&gDS1307I2CHandle);244} /* End of DS1307_I2CConfig */245
246/**247 * DS1307_Write()248 * Desc.    : Writes @value to @regAddr249 * Param.   : @value - value to write to @regAddr250 *            @regAddr - DS1307 register address to write @value to251 * Return   : None252 * Note     : N/A253 */254static void DS1307_Write(uint8_t value, uint8_t regAddr)255{256    uint8_t tx[2];257    tx[0] = regAddr;258    tx[1] = value;259    I2C_MasterTxBlocking(&gDS1307I2CHandle, tx, 2, DS1307_I2C_ADDR, 0);260
261} /* End of DS1307_Write */262
263/**264 * DS1307_Read()265 * Desc.    : Writes @value to @regAddr266 * Param.   : @regAddr - DS1307 register address to read from267 * Return   : 1-byte data received from the slave (DS1307 RTC module)268 * Note     : N/A269 */270static uint8_t DS1307_Read(uint8_t regAddr)271{272    uint8_t rxData;273    I2C_MasterTxBlocking(&gDS1307I2CHandle, ®Addr, 1, DS1307_I2C_ADDR, 0);274    I2C_MasterRxBlocking(&gDS1307I2CHandle, &rxData, 1, DS1307_I2C_ADDR, 0);275
276    return rxData;277} /* End of DS1307_Read */278
279/**280 * BcdToBinary()281 * Desc.    : Converts the passed Binary-Coded Decimal (BCD) value to binary282 * Param.   : @bcd - binary-coded decimal value to be converted into binary283 * Return   : @bcd in binary representation284 * Note     : N/A285 */286static uint8_t BcdToBinary(uint8_t bcd)287{288    uint8_t tens, ones;289
290    tens = (uint8_t)((bcd >> 4) * 10);291    ones = bcd & (uint8_t)0xF;292
293    return tens + ones;294} /* End of BcdToBinary */295
296/**297 * BinaryToBcd()298 * Desc.    : Converts the passed binary value to Binary-Coded Decimal (BCD)299 * Param.   : @binary - binary value to be converted into binary-coded decimal300 * Return   : @binary in binary-coded decimal representation301 * Note     : N/A302 */303uint8_t BinaryToBcd(uint8_t binary)304{305    uint8_t tens, ones;306    uint8_t bcd;307
308    bcd = binary;309
310    if (binary >= 10)311    {312        tens = binary / 10;313        ones = binary % 10;314        bcd = (tens << 4) | ones;315    }316
317    return bcd;318} /* End of BinaryToBcd */
lcd_hd44780u.hxxxxxxxxxx3031/*******************************************************************************2 * File     : lcd_hd44780u.c3 * Brief    : Implementation of APIs for the HD44780U 16x2 Character LCD module4 *            (4-bit interface; only DB4-7 pins of the LCD module will be used)5 * Author   : Kyungjae Lee6 * Date     : Jun 27, 20237 *8 * Note     : This code includes only the features that are necessary for my9 *            personal projects.10 ******************************************************************************/11
121314
15/* Function prototypes */16static void Write4Bits(uint8_t nibble);17static void LCD_Enable(void);18static void DelayMs(uint32_t delayInMs);19static void DelayUs(uint32_t delayInUs);20
21/**22 * LCD_Init()23 * Desc.    : Initializes GPIO pins to be used for LCD connections24 * Param.   : None25 * Return   : None26 * Note     : N/A27 */28void LCD_Init(void)29{30    GPIO_Handle_TypeDef gpioPin;31
32    /* 1. Configure the GPIO pins to be used for LCD connections -------------*/33
34    /* Configure the GPIO pin to be connected to LCD RS pin */35    gpioPin.pGPIOx = LCD_GPIO_PORT;36    gpioPin.GPIO_PinConfig.GPIO_PinMode = GPIO_PIN_MODE_OUT;37    gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_RS;38    gpioPin.GPIO_PinConfig.GPIO_PinOutType = GPIO_PIN_OUT_TYPE_PP;39    gpioPin.GPIO_PinConfig.GPIO_PinPuPdControl = GPIO_PIN_NO_PUPD;40    gpioPin.GPIO_PinConfig.GPIO_PinSpeed = GPIO_PIN_OUT_SPEED_HIGH;41    GPIO_Init(&gpioPin);42
43    /* Configure the GPIO pin to be connected to LCD RW pin */44    gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_RW;45    GPIO_Init(&gpioPin);46
47    /* Configure the GPIO pin to be connected to LCD EN pin */48    gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_EN;49    GPIO_Init(&gpioPin);50
51    /* Configure the GPIO pin to be connected to LCD D4 pin */52    gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_D4;53    GPIO_Init(&gpioPin);54
55    /* Configure the GPIO pin to be connected to LCD D5 pin */56    gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_D5;57    GPIO_Init(&gpioPin);58
59    /* Configure the GPIO pin to be connected to LCD D6 pin */60    gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_D6;61    GPIO_Init(&gpioPin);62
63    /* Configure the GPIO pin to be connected to LCD D7 pin */64    gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_D7;65    GPIO_Init(&gpioPin);66
67    /* Set the configured GPIO pins' output values to 0 */68    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RS, RESET);69    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RW, RESET);70    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_EN, RESET);71    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D4, RESET);72    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D5, RESET);73    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D6, RESET);74    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D7, RESET);75
76    /* 2. Initialize LCD module ------------------------------------------------77     * (See 'Figure 24. 4-Bit Interface' in the LCD reference manual)78     */79
80    /* Wait for more than 40 ms after Vcc rises to 2.7V */81    DelayMs(40);82
83    /* Set RS pin to 0 for LCD command */84    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RS, RESET);85
86    /* Set RW pin to 0 for writing to LCD (If you are always writing to LCD, you87     * can keep this pin connected to GND)88     */89    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RW, RESET);90
91    Write4Bits(0x3);    /* 0 0 1 1 in D7 D6 D5 D4 order */92
93    DelayMs(5);94
95    Write4Bits(0x3);96
97    DelayUs(150);98
99    Write4Bits(0x3);100    Write4Bits(0x2);101
102    /* Now, ready to send the command */103
104    /* Set to use 4 data lines, 2 lines, 5x8 char font size */105    LCD_TxInstruction(LCD_INST_4DL_2N_5X8F);106
107    /* Set display on, cursor on */108    LCD_TxInstruction(LCD_INST_DON_CURON);109
110    /* Clear display */111    LCD_ClearDisplay();112
113    /* Entry mode set */114    LCD_TxInstruction(LCD_INST_INCADD);115
116} /* End of LCD_Init */117
118/**119 * LCD_TxInstruction()120 * Desc.    : Sends passed instruction (@instruction) to LCD121 * Param.   : @instruction - LCD instruction to send122 * Return   : None123 * Note     : N/A124 */125void LCD_TxInstruction(uint8_t instruction)126{127    /* 1. Set RS=0 for LCD command */128    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RS, RESET);129
130    /* 2. Set RW=0 for write */131    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RW, RESET);132
133    Write4Bits(instruction >> 4);   /* Send the higher nibble */134    Write4Bits(instruction & 0xF);  /* Send the lower nibble */135} /* End of LCD_TxInstruction */136
137/**138 * LCD_PrintChar()139 * Desc.    : Sends a character to be printed to the LCD140 * Param.   : @ch - character to print141 * Return   : None142 * Note     : This function assumes 4-bit parallel data transmission.143 *            First, the higher nibble of the data will be sent through the data144 *            lines D4, D5, d6, d7,145 *            then, the lower nibble of the data will be sent through the data146 *            lines D4, D5, d6, d7.147 */148void LCD_PrintChar(uint8_t ch)149{150    /* 1. Set RS=1 for LCD user data */151    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RS, SET);152
153    /* 2. Set RW=0 for write */154    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RW, RESET);155
156    Write4Bits(ch >> 4);    /* Send the higher nibble */157    Write4Bits(ch & 0xF);   /* Send the lower nibble */158} /* End of LCD_TxChar */159
160/**161 * LCD_ClearDisplay()162 * Desc.    : Performs display clear routine163 * Param.   : None164 * Return   : None165 * Note     : After sending the clear display instruction, give it 2 ms as per166 *            the datasheet of LCD (See p.24 of LCD datasheet).167 */168void LCD_ClearDisplay(void)169{170    /* Clear display */171    LCD_TxInstruction(LCD_INST_CLEAR_DISPLAY);172
173    DelayMs(2); /* Wait 2 ms as per the datasheet */174} /* End of LCD_ClearDisplay */175
176/**177 * LCD_ReturnHome()178 * Desc.    : Returns the cursor to the home position179 * Param.   : None180 * Return   : None181 * Note     : After sending the clear display instruction, give it 2 ms as per182 *            the datasheet of LCD (See p.24 of LCD datasheet).183 */184void LCD_ReturnHome(void)185{186    /* Return home */187    LCD_TxInstruction(LCD_INST_RETURN_HOME);188
189    DelayMs(2); /* Wait 2 ms as per the datasheet */190} /* End of LCD_ReturnHome */191
192/**193 * LCD_PrintString()194 * Desc.    : Prints the passed string @msg to the LCD screen195 * Param.   : @msg - string to print196 * Return   : None197 * Note     : N/A198 */199void LCD_PrintString(char *msg)200{201    do202    {203        LCD_PrintChar((uint8_t)*msg++);204    }205    while (*msg != '\0');206} /* End of LCD_PrintString */207
208/**209 * LCD_SetCursor()210 * Desc.    : Sets the cursor position (@row, @column)211 * Param.   : @row - the row in which the cursor should be placed212 *            @column - the column in which the cursor should be placed213 * Return   : None214 * Note     : Row number: 1 ~ 2215 *            Column number: 1 ~ 16 assuming a 2x16 character display216 */217void LCD_SetCursor(uint8_t row, uint8_t column)218{219    column--;220
221    switch (row)222    {223    case 1:224        /* Set cursor to 1st row address and add index */225        LCD_TxInstruction((column |= 0x80));226        break;227    case 2:228        /* Set cursor to 2nd row address and add index */229        LCD_TxInstruction((column |= 0xC0));230        break;231    default:232        break;233    }234} /* End of LCD_SetCursor */235
236
237/*******************************************************************************238 * Private functions239 ******************************************************************************/240
241/**242 * DelayMs()243 * Desc.    : Spinlock delays for @delayInMs milliseconds244 * Param.   : @delayInMs - time to delay in milliseconds245 * Returns  : None246 * Note     : N/A247 */248static void DelayMs(uint32_t delayInMs)249{250    for (uint32_t i = 0; i < delayInMs * 1000; i++);251} /* End of DelayMs */252
253/**254 * DelayUs()255 * Desc.    : Spinlock delays for @delayInUs microseconds256 * Param.   : @delayInUs - time to delay in microseconds257 * Returns  : None258 * Note     : N/A259 */260static void DelayUs(uint32_t delayInUs)261{262    for (uint32_t i = 0; i < delayInUs * 1; i++);263} /* End of DelayMs */264
265/**266 * Write4Bits()267 * Desc.    : Writes 4 bits of data/command to D4, D5, D6, D7 lines268 *            (msb to D7, lsb to D4)269 * Param.   : @value -270 * Return   : None271 * Note     : N/A272 */273static void Write4Bits(uint8_t nibble)274{275    /* Write each bit of @nibble to D4-D7 lines */276    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D4, (nibble >> 0) & 0x1);277    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D5, (nibble >> 1) & 0x1);278    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D6, (nibble >> 2) & 0x1);279    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D7, (nibble >> 3) & 0x1);280
281    /* After writing every nibble to the data lines, give the LCD time to latch282     * that data inside the LCD283     */284    /* Make high-to-low transition on EN pin (See the timing diagram) */285    LCD_Enable();286
287} /* End of Write4Bits */288
289/**290 * LCD_Enable()291 * Desc.    : Makes high-to-low transition on the EN line292 * Param.   : None293 * Return   : None294 * Note     : For the instruction execution time, give any value that is greater295 *            than 32 micro-seconds.296 */297static void LCD_Enable(void)298{299    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_EN, SET);300    DelayUs(10);301    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_EN, RESET);302    DelayUs(100);303} /* End of LCD_Enable */
lcd_hd44780u.cxxxxxxxxxx3021/*******************************************************************************2 * Filename     : lcd_hd44780u.c3 * Description  : Implementation of APIs for 16x2 Character LCD module4 *                (4-bit interface; only DB4-DB7 pins of the LCD module will be5 *                used)6 * Author       : Kyungjae Lee7 * History      : Jun 27, 2023 - Created file8 ******************************************************************************/9
101112
13/* Function prototypes */14static void Write4Bits(uint8_t nibble);15static void LCD_Enable(void);16static void DelayMs(uint32_t delayInMs);17static void DelayUs(uint32_t delayInUs);18
19/**20 * LCD_Init()21 * Desc.    : Initializes GPIO pins to be used for LCD connections22 * Param.   : None23 * Return   : None24 * Note     : N/A25 */26void LCD_Init(void)27{28    GPIO_Handle_TypeDef gpioPin;29
30    /* 1. Configure the GPIO pins to be used for LCD connections -------------*/31
32    /* Configure the GPIO pin to be connected to LCD RS pin */33    gpioPin.pGPIOx = LCD_GPIO_PORT;34    gpioPin.GPIO_PinConfig.GPIO_PinMode = GPIO_PIN_MODE_OUT;35    gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_RS;36    gpioPin.GPIO_PinConfig.GPIO_PinOutType = GPIO_PIN_OUT_TYPE_PP;37    gpioPin.GPIO_PinConfig.GPIO_PinPuPdControl = GPIO_PIN_NO_PUPD;38    gpioPin.GPIO_PinConfig.GPIO_PinSpeed = GPIO_PIN_OUT_SPEED_HIGH;39    GPIO_Init(&gpioPin);40
41    /* Configure the GPIO pin to be connected to LCD RW pin */42    gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_RW;43    GPIO_Init(&gpioPin);44
45    /* Configure the GPIO pin to be connected to LCD EN pin */46    gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_EN;47    GPIO_Init(&gpioPin);48
49    /* Configure the GPIO pin to be connected to LCD D4 pin */50    gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_D4;51    GPIO_Init(&gpioPin);52
53    /* Configure the GPIO pin to be connected to LCD D5 pin */54    gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_D5;55    GPIO_Init(&gpioPin);56
57    /* Configure the GPIO pin to be connected to LCD D6 pin */58    gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_D6;59    GPIO_Init(&gpioPin);60
61    /* Configure the GPIO pin to be connected to LCD D7 pin */62    gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_D7;63    GPIO_Init(&gpioPin);64
65    /* Set the configured GPIO pins' output values to 0 */66    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RS, RESET);67    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RW, RESET);68    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_EN, RESET);69    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D4, RESET);70    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D5, RESET);71    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D6, RESET);72    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D7, RESET);73
74    /* 2. Initialize LCD module ------------------------------------------------75     * (See 'Figure 24. 4-Bit Interface' in the LCD reference manual)76     */77
78    /* Wait for more than 40 ms after Vcc rises to 2.7V */79    DelayMs(40);80
81    /* Set RS pin to 0 for LCD command */82    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RS, RESET);83
84    /* Set RW pin to 0 for writing to LCD (If you are always writing to LCD, you85     * can keep this pin connected to GND)86     */87    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RW, RESET);88
89    Write4Bits(0x3);    /* 0 0 1 1 in D7 D6 D5 D4 order */90
91    DelayMs(5);92
93    Write4Bits(0x3);94
95    DelayUs(150);96
97    Write4Bits(0x3);98    Write4Bits(0x2);99
100    /* Now, ready to send the command */101
102    /* Set to use 4 data lines, 2 lines, 5x8 char font size */103    LCD_TxInstruction(LCD_INST_4DL_2N_5X8F);104
105    /* Set display on, cursor on */106    LCD_TxInstruction(LCD_INST_DON_CURON);107
108    /* Clear display */109    LCD_ClearDisplay();110
111    /* Entry mode set */112    LCD_TxInstruction(LCD_INST_INCADD);113
114} /* End of LCD_Init */115
116/**117 * LCD_TxInstruction()118 * Desc.    : Sends passed instruction (@instruction) to LCD119 * Param.   : @instruction - LCD instruction to send120 * Return   : None121 * Note     : N/A122 */123void LCD_TxInstruction(uint8_t instruction)124{125    /* 1. Set RS=0 for LCD command */126    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RS, RESET);127
128    /* 2. Set RW=0 for write */129    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RW, RESET);130
131    Write4Bits(instruction >> 4);   /* Send the higher nibble */132    Write4Bits(instruction & 0xF);  /* Send the lower nibble */133} /* End of LCD_TxInstruction */134
135/**136 * LCD_PrintChar()137 * Desc.    : Sends a character to be printed to the LCD138 * Param.   : @ch - character to print139 * Return   : None140 * Note     : This function assumes 4-bit parallel data transmission.141 *            First, the higher nibble of the data will be sent through the data142 *            lines D4, D5, d6, d7,143 *            then, the lower nibble of the data will be sent through the data144 *            lines D4, D5, d6, d7.145 */146void LCD_PrintChar(uint8_t ch)147{148    /* 1. Set RS=1 for LCD user data */149    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RS, SET);150
151    /* 2. Set RW=0 for write */152    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RW, RESET);153
154    Write4Bits(ch >> 4);    /* Send the higher nibble */155    Write4Bits(ch & 0xF);   /* Send the lower nibble */156} /* End of LCD_TxChar */157
158/**159 * LCD_ClearDisplay()160 * Desc.    : Performs display clear routine161 * Param.   : None162 * Return   : None163 * Note     : After sending the clear display instruction, give it 2 ms as per164 *            the datasheet of LCD (See p.24 of LCD datasheet).165 */166void LCD_ClearDisplay(void)167{168    /* Clear display */169    LCD_TxInstruction(LCD_INST_CLEAR_DISPLAY);170
171    DelayMs(2); /* Wait 2 ms as per the datasheet */172}173
174/**175 * LCD_ReturnHome()176 * Desc.    : Returns the cursor to the home position177 * Param.   : None178 * Return   : None179 * Note     : After sending the clear display instruction, give it 2 ms as per180 *            the datasheet of LCD (See p.24 of LCD datasheet).181 */182void LCD_ReturnHome(void)183{184    /* Return home */185    LCD_TxInstruction(LCD_INST_RETURN_HOME);186
187    DelayMs(2); /* Wait 2 ms as per the datasheet */188} /* End of LCD_ReturnHome */189
190/**191 * LCD_PrintString()192 * Desc.    : Prints the passed string @msg to the LCD screen193 * Param.   : @msg - string to print194 * Return   : None195 * Note     : N/A196 */197void LCD_PrintString(char *msg)198{199    do200    {201        LCD_PrintChar((uint8_t)*msg++);202    }203    while (*msg != '\0');204} /* End of LCD_PrintString */205
206/**207 * LCD_SetCursor()208 * Desc.    : Sets the cursor position (@row, @column)209 * Param.   : @row - the row in which the cursor should be placed210 *            @column - the column in which the cursor should be placed211 * Return   : None212 * Note     : Row number: 1 ~ 2213 *            Column number: 1 ~ 16 assuming a 2x16 character display214 */215void LCD_SetCursor(uint8_t row, uint8_t column)216{217    column--;218
219    switch (row)220    {221    case 1:222        /* Set cursor to 1st row address and add index */223        LCD_TxInstruction((column |= 0x80));224        break;225    case 2:226        /* Set cursor to 2nd row address and add index */227        LCD_TxInstruction((column |= 0xC0));228        break;229    default:230        break;231    }232} /* End of LCD_SetCursor */233
234
235
236/*******************************************************************************237 * Private functions238 ******************************************************************************/239
240/**241 * DelayMs()242 * Desc.    : Spinlock delays for @delayInMs milliseconds243 * Param.   : @delayInMs - time to delay in milliseconds244 * Returns  : None245 * Note     : N/A246 */247static void DelayMs(uint32_t delayInMs)248{249    for (uint32_t i = 0; i < delayInMs * 1000; i++);250} /* End of DelayMs */251
252/**253 * DelayUs()254 * Desc.    : Spinlock delays for @delayInUs microseconds255 * Param.   : @delayInUs - time to delay in microseconds256 * Returns  : None257 * Note     : N/A258 */259static void DelayUs(uint32_t delayInUs)260{261    for (uint32_t i = 0; i < delayInUs * 1; i++);262} /* End of DelayMs */263
264/**265 * Write4Bits()266 * Desc.    : Writes 4 bits of data/command to D4, D5, D6, D7 lines267 *            (msb to D7, lsb to D4)268 * Param.   : @value -269 * Return   : None270 * Note     : N/A271 */272static void Write4Bits(uint8_t nibble)273{274    /* Write each bit of @nibble to D4-D7 lines */275    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D4, (nibble >> 0) & 0x1);276    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D5, (nibble >> 1) & 0x1);277    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D6, (nibble >> 2) & 0x1);278    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D7, (nibble >> 3) & 0x1);279
280    /* After writing every nibble to the data lines, give the LCD time to latch281     * that data inside the LCD282     */283    /* Make high-to-low transition on EN pin (See the timing diagram) */284    LCD_Enable();285
286} /* End of Write4Bits */287
288/**289 * LCD_Enable()290 * Desc.    : Makes high-to-low transition on the EN line291 * Param.   : None292 * Return   : None293 * Note     : For the instruction execution time, give any value that is greater294 *            than 32 micro-seconds.295 */296static void LCD_Enable(void)297{298    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_EN, SET);299    DelayUs(10);300    GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_EN, RESET);301    DelayUs(100);302} /* End of LCD_Enable */