Created
February 21, 2018 16:11
-
-
Save cr1901/fea469d4b64487c5cb925b42300deba7 to your computer and use it in GitHub Desktop.
2013 MSP430 LCD Demo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <msp430g2231.h> | |
//const char * lcd_string = "Hello World!"; | |
#define DB7 BIT7 | |
#define DB6 BIT6 | |
#define DB5 BIT5 | |
#define DB4 BIT4 | |
#define ADDR(_x) _x << 4 | |
#define RS BIT0 | |
#define EN BIT1 | |
#define PAUSE(_x) __delay_cycles(_x) | |
volatile int counter = 0; | |
volatile int elapsed = 0; | |
volatile int centiseconds = 0; | |
volatile int seconds = 0; | |
volatile int minutes = 0; | |
volatile int hours = 0; | |
char time[] = "00:00:00"; | |
char ascii_number[7] = {' '}; | |
//Courtesy: https://sites.google.com/site/cacheattack/msp-projects/msp430-launchpad-with-lcd-module | |
#define LCM_DIR P1DIR | |
#define LCM_OUT P1OUT | |
// | |
// Define symbolic LCM - MCU pin mappings | |
// We've set DATA PIN TO 4,5,6,7 for easy translation | |
// | |
#define LCM_PIN_RS BIT0 // P1.0 | |
#define LCM_PIN_EN BIT1 // P1.1 | |
#define LCM_PIN_D7 BIT5 // P1.7 | |
#define LCM_PIN_D6 BIT4 // P1.6 | |
#define LCM_PIN_D5 BIT3 // P1.5 | |
#define LCM_PIN_D4 BIT2 // P1.4 | |
#define LCM_PIN_MASK ((LCM_PIN_RS | LCM_PIN_EN | LCM_PIN_D7 | LCM_PIN_D6 | LCM_PIN_D5 | LCM_PIN_D4)) | |
#define FALSE 0 | |
#define TRUE 1 | |
// | |
// Routine Desc: | |
// | |
// This is the function that must be called | |
// whenever the LCM needs to be told to | |
// scan it's data bus. | |
// | |
// Parameters: | |
// | |
// void. | |
// | |
// Return | |
// | |
// void. | |
// | |
void PulseLcm() | |
{ | |
// | |
// pull EN bit low | |
// | |
LCM_OUT &= ~LCM_PIN_EN; | |
PAUSE(200); | |
// | |
// pull EN bit high | |
// | |
LCM_OUT |= LCM_PIN_EN; | |
PAUSE(200); | |
// | |
// pull EN bit low again | |
// | |
LCM_OUT &= (~LCM_PIN_EN); | |
PAUSE(200); | |
} | |
// | |
// Routine Desc: | |
// | |
// Send a byte on the data bus in the 4 bit mode | |
// This requires sending the data in two chunks. | |
// The high nibble first and then the low nible | |
// | |
// Parameters: | |
// | |
// ByteToSend - the single byte to send | |
// | |
// IsData - set to TRUE if the byte is character data | |
// FALSE if its a command | |
// | |
// Return | |
// | |
// void. | |
// | |
void SendByte(char ByteToSend, int IsData) | |
{ | |
// | |
// clear out all pins | |
// | |
LCM_OUT &= (~LCM_PIN_MASK); | |
// | |
// set High Nibble (HN) - | |
// usefulness of the identity mapping | |
// apparent here. We can set the | |
// DB7 - DB4 just by setting P1.7 - P1.4 | |
// using a simple assignment | |
// | |
LCM_OUT |= ((ByteToSend & 0xF0) >> 2); | |
if (IsData == TRUE) | |
{ | |
LCM_OUT |= LCM_PIN_RS; | |
} | |
else | |
{ | |
LCM_OUT &= ~LCM_PIN_RS; | |
} | |
// | |
// we've set up the input voltages to the LCM. | |
// Now tell it to read them. | |
// | |
PulseLcm(); | |
// | |
// set Low Nibble (LN) - | |
// usefulness of the identity mapping | |
// apparent here. We can set the | |
// DB7 - DB4 just by setting P1.7 - P1.4 | |
// using a simple assignment | |
// | |
LCM_OUT &= (~LCM_PIN_MASK); | |
LCM_OUT |= ((ByteToSend & 0x0F) << 2); | |
if (IsData == TRUE) | |
{ | |
LCM_OUT |= LCM_PIN_RS; | |
} | |
else | |
{ | |
LCM_OUT &= ~LCM_PIN_RS; | |
} | |
// | |
// we've set up the input voltages to the LCM. | |
// Now tell it to read them. | |
// | |
PulseLcm(); | |
} | |
// | |
// Routine Desc: | |
// | |
// Set the position of the cursor on the screen | |
// | |
// Parameters: | |
// | |
// Row - zero based row number | |
// | |
// Col - zero based col number | |
// | |
// Return | |
// | |
// void. | |
// | |
void LcmSetCursorPosition(char Row, char Col) | |
{ | |
char address; | |
// | |
// construct address from (Row, Col) pair | |
// | |
if (Row == 0) | |
{ | |
address = 0; | |
} | |
else | |
{ | |
address = 0x40; | |
} | |
address |= Col; | |
SendByte(0x80 | address, FALSE); | |
} | |
// | |
// Routine Desc: | |
// | |
// Clear the screen data and return the | |
// cursor to home position | |
// | |
// Parameters: | |
// | |
// void. | |
// | |
// Return | |
// | |
// void. | |
// | |
void ClearLcmScreen() | |
{ | |
// | |
// Clear display, return home | |
// | |
SendByte(0x01, FALSE); | |
SendByte(0x02, FALSE); | |
} | |
// | |
// Routine Desc: | |
// | |
// Initialize the LCM after power-up. | |
// | |
// Note: This routine must not be called twice on the | |
// LCM. This is not so uncommon when the power | |
// for the MCU and LCM are separate. | |
// | |
// Parameters: | |
// | |
// void. | |
// | |
// Return | |
// | |
// void. | |
// | |
void InitializeLcm(void) | |
{ | |
// | |
// set the MSP pin configurations | |
// and bring them to low | |
// | |
LCM_DIR |= LCM_PIN_MASK; | |
LCM_OUT &= ~(LCM_PIN_MASK); | |
// | |
// wait for the LCM to warm up and reach | |
// active regions. Remember MSPs can power | |
// up much faster than the LCM. | |
// | |
PAUSE(100000); | |
// | |
// initialize the LCM module | |
// | |
// 1. Set 4-bit input | |
// | |
LCM_OUT &= ~LCM_PIN_RS; | |
LCM_OUT &= ~LCM_PIN_EN; | |
/* Switch to 8-bit mode in case reset occurred. */ | |
LCM_OUT = (0x30 >> 2); | |
PulseLcm(); | |
PulseLcm(); | |
LCM_OUT = (0x20 >> 2); | |
PulseLcm(); | |
// | |
// set 4-bit input - second time. | |
// (as reqd by the spec.) | |
// | |
SendByte(0x28, FALSE); | |
// | |
// 2. Display on, cursor on, blink cursor | |
//0x0E- Cursor not blinking | |
SendByte(0x0F, FALSE); | |
// | |
// 3. Cursor move auto-increment | |
// | |
SendByte(0x06, FALSE); | |
} | |
// | |
// Routine Desc | |
// | |
// Print a string of characters to the screen | |
// | |
// Parameters: | |
// | |
// Text - null terminated string of chars | |
// | |
// Returns | |
// | |
// void. | |
// | |
void PrintStr(char *Text) | |
{ | |
char *c; | |
c = Text; | |
while ((c != 0) && (*c != 0)) | |
{ | |
SendByte(*c, TRUE); | |
c++; | |
} | |
} | |
//http://www.strudel.org.uk/itoa/ | |
/** | |
* C++ version 0.4 char* style "itoa": | |
* Written by Lukás Chmela | |
* Released under GPLv3. | |
*/ | |
char* itoa(int value, char* result, int base) { | |
// check that the base if valid | |
if (base < 2 || base > 16) { *result = '\0'; return result; } | |
char* ptr = result, *ptr1 = result, tmp_char; | |
int tmp_value; | |
do { | |
tmp_value = value; | |
value /= base; | |
*ptr++ = "fedcba9876543210123456789abcdef" [15 + (tmp_value - value * base)]; | |
} while ( value ); | |
// Apply negative sign | |
if (tmp_value < 0) *ptr++ = '-'; | |
*ptr-- = '\0'; | |
while(ptr1 < ptr) { | |
tmp_char = *ptr; | |
*ptr--= *ptr1; | |
*ptr1++ = tmp_char; | |
} | |
return result; | |
} | |
int main() | |
{ | |
//unsigned int i = 0; | |
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer. | |
//TACTL = MC_0; //The output needs to be stopped! | |
//__delay_cycles(1000000); | |
//Set Auxilary clock to internal LFO | |
BCSCTL3 &= ~LFXT1S_0; //Don't mess with other bits | |
BCSCTL3 |= LFXT1S_2; /* Set ACLK to Very Low Power Oscillator- | |
supposedly needs to be external, according to pg. 44 of device datasheet. */ | |
BCSCTL1 &= ~DIVA_0; // | |
BCSCTL1 |= DIVA_3; //Set ACLK to lowest speed (divide by 8 from 12000 Hz) | |
//TACCTL1 = ~CAP + | |
TACTL = TASSEL_1 + ID_2 + MC_1; //Use ACLK, divide by 4, use up mode. | |
//P1DIR |= 0x40; // P1DIR configures direction port pin (DIR) output or input. | |
// 1 is output, 0 is input. 0x40 is Green LED | |
TACCR0 = 2; // 188 approx 1Hz (12000/32) Period: TACCR0 + 1... might not be right for 50% duty cycle... | |
TACCTL0 = CCIE; | |
TACCR1 = 1; // 50% duty cycle | |
TACCTL1 = OUTMOD_3; //Compare Mode, Toggle output each time either TACCR1 or TACCR0 is reached. | |
P2SEL &= ~0xC0; //This is required: http://e2e.ti.com/support/microcontrollers/msp430/f/166/t/19225.aspx | |
/* Device datasheet does not say so, however... */ | |
P2SEL |= BIT6; //http://e2e.ti.com/support/microcontrollers/msp430/f/166/t/36123.aspx | |
//P2OUT &= ~BIT6; //Set the PWM to 0 to discharge the charge pump and LCD power supply. | |
//Weird effects happen otherwise! | |
P2DIR |= BIT6; //Use peripheral Timer A Capture Control Out 1 and set port 2.6 as output. | |
//__delay_cycles(2000000); | |
InitializeLcm(); | |
//__delay_cycles(1000000); | |
ClearLcmScreen(); | |
PrintStr("Hello World!"); | |
LcmSetCursorPosition(1, 0); | |
PrintStr("Time: "); | |
//itoa(elapsed, ascii_number, 10); | |
//PrintStr(ascii_number); | |
__bis_SR_register(LPM3_bits + GIE); | |
/* while(1) | |
{ | |
} */ | |
/* while (1) | |
{ | |
__delay_cycles(1000); | |
} */ | |
/* while(1) { | |
//What does the C standard say about assignments in if statements? | |
// i.e. if(P1IN &= 0x08) | |
if(P1IN & 0x08) | |
{ | |
P1OUT |= 0x40; | |
//P2OUT |= 0x40; | |
} | |
else // Toggle P1.6 | |
{ | |
P1OUT &= 0x00; | |
//P2OUT &= 0x00; | |
} | |
// P1OUT register holds the status of the LED. | |
// Delay between Green LED toggles. | |
} */ | |
} | |
#pragma vector=TIMERA0_VECTOR | |
__interrupt void Timer_A0 (void) | |
{ | |
// Timer A0 interrupt service routine | |
centiseconds = (centiseconds + 1)%125; //3 cycles per period... 125Hz | |
if(centiseconds == 0) | |
{ | |
seconds = (seconds + 1)%60; | |
if(seconds < 10) | |
{ | |
time[6] = '0'; | |
itoa(seconds, &time[7], 10); | |
} | |
else | |
{ | |
itoa(seconds, &time[6], 10); | |
} | |
if(seconds == 0) | |
{ | |
minutes = (minutes + 1)%60; | |
if(minutes < 10) | |
{ | |
time[3] = '0'; | |
itoa(minutes, &time[4], 10); | |
} | |
else | |
{ | |
itoa(minutes, &time[3], 10); | |
} | |
time[5] = ':'; | |
if(minutes == 0) | |
{ | |
hours = (hours + 1)%24; | |
if(hours < 10) | |
{ | |
time[0] = '0'; | |
itoa(hours, &time[1], 10); | |
} | |
else | |
{ | |
itoa(hours, time, 10); | |
} | |
time[2] = ':'; | |
} | |
} | |
LcmSetCursorPosition(1, 6); | |
PrintStr(time); | |
} | |
} | |
/* #pragma vector=TIMERA0_VECTOR | |
__interrupt void Timer_A0 (void) | |
{ | |
// Timer A0 interrupt service routine | |
counter = (counter + 1)%125; //3 cycles per period | |
if(counter == 0) | |
{ | |
elapsed += 1; | |
LcmSetCursorPosition(1, 6); | |
itoa(elapsed, ascii_number, 10); | |
PrintStr(ascii_number); | |
} | |
} */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment