大家好、我希望有人可以帮助我配置 MSP430Fr4133以便与 SSD1306 I2C 显示屏配合使用?
// I2C.c #include "i2c.h" #include <msp430fr4133.h> #include <stdint.h> #define SDA BIT2 // i2c sda P5.2 #define SCL BIT3 // i2c scl P5.3 unsigned char* PTxData; // Pointer to TX data unsigned char TxByteCtr; // number of bytes to TX void i2c_init(void) { P5SEL0 |= SCL + SDA; // Assign I2C pins to USCI_B0 UCB0CTL1 |= UCSWRST; // Enable SW reset UCB0CTLW0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset UCB0BRW = 10; // fSCL = SMCLK/10 = ~100kHz with SMCLK 1MHz UCB0BRW = 0; UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation UCB0IE |= UCTXIE0; // Enable TX interrupt } // end i2c_init void i2c_write(unsigned char slave_address, unsigned char *DataBuffer, unsigned char ByteCtr) { UCB0I2CSA = slave_address; PTxData = DataBuffer; TxByteCtr = ByteCtr; while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent __bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts // Remain in LPM0 until all data is TX'd } #pragma vector = USCI_B0_VECTOR __interrupt void USCIB0_ISR(void){ switch(__even_in_range(UCB0IV,0x1E)) { case USCI_NONE: break; // Vector 0: No interrupts break; case USCI_I2C_UCALIFG: break; case USCI_I2C_UCNACKIFG: break; case USCI_I2C_UCSTTIFG: break; // Vector 6: STTIFG break; case USCI_I2C_UCSTPIFG: break; // Vector 8: STPIFG break; case USCI_I2C_UCRXIFG3: break; // Vector 10: RXIFG3 break; case USCI_I2C_UCTXIFG3: break; // Vector 14: TXIFG3 break; case USCI_I2C_UCRXIFG2: break; // Vector 16: RXIFG2 break; case USCI_I2C_UCTXIFG2: break; // Vector 18: TXIFG2 break; case USCI_I2C_UCRXIFG1: break; // Vector 20: RXIFG1 break; case USCI_I2C_UCTXIFG1: break; // Vector 22: TXIFG1 break; case USCI_I2C_UCRXIFG0: break; // Vector 24: RXIFG0 break; case USCI_I2C_UCTXIFG0: if (TxByteCtr) { // Check TX byte counter UCB0TXBUF = *PTxData++; // Load TX buffer TxByteCtr--; // Decrement TX byte counter } else { UCB0CTL1 |= UCTXSTP; // I2C stop condition UCB0IE &= ~UCTXIE0; // Clear USCI_B0 TX int flag __bic_SR_register_on_exit(CPUOFF);// Exit LPM0 } break; // Vector 26: TXIFG0 break; case USCI_I2C_UCBCNTIFG: break; // Vector 28: BCNTIFG case USCI_I2C_UCCLTOIFG: break; // Vector 30: clock low timeout case USCI_I2C_UCBIT9IFG: break; // Vector 32: 9th bit default: break; } } //I2C.h #ifndef I2C_H_ #define I2C_H_ #include <msp430fr4133.h> /* ==================================================================== * I2C Prototype Definitions * ==================================================================== */ void i2c_init(void); void i2c_write(unsigned char, unsigned char *, unsigned char); #endif /* I2C_H_ */ /* * ssd1306.h */ #ifndef SSD1306_H_ #define SSD1306_H_ #include <msp430fr4133.h> #include <stdint.h> #include <string.h> #include "i2c.h" /* ==================================================================== * Horizontal Centering Number Array * ==================================================================== */ #define HCENTERUL_OFF 0 #define HCENTERUL_ON 1 /* ==================================================================== * SSD1306 OLED Settings and Command Definitions * ==================================================================== */ #define SSD1306_I2C_ADDRESS 0x3C #define SSD1306_LCDWIDTH 128 #define SSD1306_LCDHEIGHT 64 #define SSD1306_128_64 #define SSD1306_SETCONTRAST 0x81 #define SSD1306_DISPLAYALLON_RESUME 0xA4 #define SSD1306_DISPLAYALLON 0xA5 #define SSD1306_NORMALDISPLAY 0xA6 #define SSD1306_INVERTDISPLAY 0xA7 #define SSD1306_DISPLAYOFF 0xAE #define SSD1306_DISPLAYON 0xAF #define SSD1306_SETDISPLAYOFFSET 0xD3 #define SSD1306_SETCOMPINS 0xDA #define SSD1306_SETVCOMDETECT 0xDB #define SSD1306_SETDISPLAYCLOCKDIV 0xD5 #define SSD1306_SETPRECHARGE 0xD9 #define SSD1306_SETMULTIPLEX 0xA8 #define SSD1306_SETLOWCOLUMN 0x00 #define SSD1306_SETHIGHCOLUMN 0x10 #define SSD1306_SETSTARTLINE 0x40 #define SSD1306_MEMORYMODE 0x20 #define SSD1306_COLUMNADDR 0x21 #define SSD1306_PAGEADDR 0x22 #define SSD1306_COMSCANINC 0xC0 #define SSD1306_COMSCANDEC 0xC8 #define SSD1306_SEGREMAP 0xA0 #define SSD1306_CHARGEPUMP 0x8D #define SSD1306_EXTERNALVCC 0x1 #define SSD1306_SWITCHCAPVCC 0x2 // currently no scroll functionality, left for possible future use #define SSD1306_ACTIVATE_SCROLL 0x2F #define SSD1306_DEACTIVATE_SCROLL 0x2E #define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3 #define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26 #define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27 #define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29 #define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A /* ==================================================================== * SSD1306 OLED Prototype Definitions * ==================================================================== */ void ssd1306_init(void); void ssd1306_command(unsigned char); void ssd1306_clearDisplay(void); void ssd1306_setPosition(uint8_t, uint8_t); void ssd1306_printText(uint8_t, uint8_t, char *); void ssd1306_printTextBlock(uint8_t, uint8_t, char *); void ssd1306_printUI32(uint8_t, uint8_t, uint32_t, uint8_t); uint8_t digits(uint32_t); void ultoa(uint32_t, char *); void reverse(char *); #endif /* SSD1306_H_ */ /* * ssd1306.c */ #include "ssd1306.h" #include <msp430fr4133.h> #include <stdint.h> #include "font_5x7.h" #include "i2c.h" /* ==================================================================== * Horizontal Centering Number Array * ==================================================================== */ unsigned char buffer[17]; // buffer for data transmission to screen const unsigned char HcenterUL[] = { // Horizontally center number with separators on screen 0, // 0 digits, not used but included to size array correctly 61, // 1 digit 58, // 2 digits 55, // 3 digits 49, // 4 digits and 1 separator 46, // 5 digits and 1 separator 43, // 6 digits and 1 separator 37, // 7 digits and 2 separators 34, // 8 digits and 2 separators 31, // 9 digits and 2 separators 25 // 10 digits and 3 separators }; void ssd1306_init(void) { // SSD1306 init sequence ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5 ssd1306_command(0x80); // the suggested ratio 0x80 ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8 ssd1306_command(SSD1306_LCDHEIGHT - 1); ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3 ssd1306_command(0x0); // no offset ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0 ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D ssd1306_command(0x14); // generate high voltage from 3.3v line internally ssd1306_command(SSD1306_MEMORYMODE); // 0x20 ssd1306_command(0x00); // 0x0 act like ks0108 ssd1306_command(SSD1306_SEGREMAP | 0x1); ssd1306_command(SSD1306_COMSCANDEC); ssd1306_command(SSD1306_SETCOMPINS); // 0xDA ssd1306_command(0x12); ssd1306_command(SSD1306_SETCONTRAST); // 0x81 ssd1306_command(0xCF); ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9 ssd1306_command(0xF1); ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB ssd1306_command(0x40); ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4 ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6 ssd1306_command(SSD1306_DEACTIVATE_SCROLL); ssd1306_command(SSD1306_DISPLAYON); //--turn on oled panel } // end ssd1306_init void ssd1306_command(unsigned char command) { buffer[0] = 0x80; buffer[1] = command; i2c_write(SSD1306_I2C_ADDRESS, buffer, 2); } // end ssd1306_command void ssd1306_clearDisplay(void) { ssd1306_setPosition(0, 0); uint8_t i; for (i = 64; i > 0; i--) { // count down for loops when possible for ULP uint8_t x; for(x = 16; x > 0; x--) { if (x == 1) { buffer[x-1] = 0x40; } else { buffer[x-1] = 0x0; } } i2c_write(SSD1306_I2C_ADDRESS, buffer, 17); } } // end ssd1306_clearDisplay void ssd1306_setPosition(uint8_t column, uint8_t page) { if (column > 128) { column = 0; // constrain column to upper limit } if (page > 8) { page = 0; // constrain page to upper limit } ssd1306_command(SSD1306_COLUMNADDR); ssd1306_command(column); // Column start address (0 = reset) ssd1306_command(SSD1306_LCDWIDTH-1); // Column end address (127 = reset) ssd1306_command(SSD1306_PAGEADDR); ssd1306_command(page); // Page start address (0 = reset) ssd1306_command(7); // Page end address } // end ssd1306_setPosition void ssd1306_printText(uint8_t x, uint8_t y, char *ptString) { ssd1306_setPosition(x, y); while (*ptString != '\0') { buffer[0] = 0x40; if ((x + 5) >= 127) { // char will run off screen x = 0; // set column to 0 y++; // jump to next page ssd1306_setPosition(x, y); // send position change to oled } uint8_t i; for(i = 0; i< 5; i++) { buffer[i+1] = font_5x7[*ptString - ' '][i]; } buffer[6] = 0x0; i2c_write(SSD1306_I2C_ADDRESS, buffer, 7); ptString++; x+=6; } } // end ssd1306_printText void ssd1306_printTextBlock(uint8_t x, uint8_t y, char *ptString) { char word[12]; uint8_t i; uint8_t endX = x; while (*ptString != '\0'){ i = 0; while ((*ptString != ' ') && (*ptString != '\0')) { word[i] = *ptString; ptString++; i++; endX += 6; } word[i++] = '\0'; if (endX >= 127) { x = 0; y++; ssd1306_printText(x, y, word); endX = (i * 6); x = endX; } else { ssd1306_printText(x, y, word); endX += 6; x = endX; } ptString++; } } void ssd1306_printUI32( uint8_t x, uint8_t y, uint32_t val, uint8_t Hcenter ) { char text[14]; ultoa(val, text); if (Hcenter) { ssd1306_printText(HcenterUL[digits(val)], y, text); } else { ssd1306_printText(x, y, text); } } // end ssd1306_printUI32 uint8_t digits(uint32_t n) { if (n < 10) { return 1; } else if (n < 100) { return 2; } else if (n < 1000) { return 3; } else if (n < 10000) { return 4; } else if (n < 100000) { return 5; } else if (n < 1000000) { return 6; } else if (n < 10000000) { return 7; } else if (n < 100000000) { return 8; } else if (n < 1000000000) { return 9; } else { return 10; } } // end digits void ultoa(uint32_t val, char *string) { uint8_t i = 0; uint8_t j = 0; // use do loop to convert val to string do { if (j==3) { // we have reached a separator position string[i++] = ','; // add a separator to the number string j=0; // reset separator indexer thingy } string[i++] = val%10 + '0'; // add the ith digit to the number string j++; // increment counter to keep track of separator placement } while ((val/=10) > 0); string[i++] = '\0'; // add termination to string reverse(string); // string was built in reverse, fix that } // end ultoa void reverse(char *s) { uint8_t i, j; uint8_t c; for (i = 0, j = strlen(s)-1; i<j; i++, j--) { c = s[i]; s[i] = s[j]; s[j] = c; } } // end reverse /* * font_5x7.h */ #ifndef FONT_5X7_H_ #define FONT_5X7_H_ const unsigned char font_5x7[96][5] = {{0x00, 0x00, 0x00, 0x00, 0x00}, // space {0x00, 0x00, 0x4F, 0x00, 0x00}, // ! {0x00, 0x07, 0x00, 0x07, 0x00}, // " {0x14, 0x7F, 0x14, 0x7F, 0x14}, // # {0x24, 0x2A, 0x7F, 0x2A, 0x12}, // $ {0x23, 0x13, 0x08, 0x64, 0x62}, // % {0x36, 0x49, 0x55, 0x22, 0x50}, // & {0x00, 0x05, 0x03, 0x00, 0x00}, // ' {0x00, 0x1C, 0x22, 0x41, 0x00}, // ( {0x00, 0x41, 0x22, 0x1C, 0x00}, // ) {0x14, 0x08, 0x3E, 0x08, 0x14}, // * {0x08, 0x08, 0x3E, 0x08, 0x08}, // + {0x00, 0x50, 0x30, 0x00, 0x00}, // , {0x08, 0x08, 0x08, 0x08, 0x08}, // - {0x00, 0x60, 0x60, 0x00, 0x00}, // . {0x20, 0x10, 0x08, 0x04, 0x02}, // / {0x3E, 0x51, 0x49, 0x45, 0x3E}, // 0 {0x00, 0x42, 0x7F, 0x40, 0x00}, // 1 {0x42, 0x61, 0x51, 0x49, 0x46}, // 2 {0x21, 0x41, 0x45, 0x4B, 0x31}, // 3 {0x18, 0x14, 0x12, 0x7F, 0x10}, // 4 {0x27, 0x49, 0x49, 0x49, 0x31}, // 5 {0x3C, 0x4A, 0x49, 0x49, 0x30}, // 6 {0x01, 0x71, 0x09, 0x05, 0x03}, // 7 {0x36, 0x49, 0x49, 0x49, 0x36}, // 8 {0x06, 0x49, 0x49, 0x29, 0x1E}, // 9 {0x00, 0x36, 0x36, 0x00, 0x00}, // : {0x00, 0x56, 0x36, 0x00, 0x00}, // ; {0x08, 0x14, 0x22, 0x41, 0x00}, // < {0x14, 0x14, 0x14, 0x14, 0x14}, // = {0x00, 0x41, 0x22, 0x14, 0x08}, // > {0x02, 0x01, 0x51, 0x09, 0x06}, // ? {0x32, 0x49, 0x79, 0x41, 0x3E}, // @ {0x7E, 0x11, 0x11, 0x11, 0x7E}, // A {0x7F, 0x49, 0x49, 0x49, 0x36}, // B {0x3E, 0x41, 0x41, 0x41, 0x22}, // C {0x7F, 0x41, 0x41, 0x22, 0x1C}, // D {0x7F, 0x49, 0x49, 0x49, 0x41}, // E {0x7F, 0x09, 0x09, 0x09, 0x01}, // F {0x3E, 0x41, 0x49, 0x49, 0x7A}, // G {0x7F, 0x08, 0x08, 0x08, 0x7F}, // H {0x00, 0x41, 0x7F, 0x41, 0x00}, // I {0x20, 0x40, 0x41, 0x3F, 0x01}, // J {0x7F, 0x08, 0x14, 0x22, 0x41}, // K {0x7F, 0x40, 0x40, 0x40, 0x40}, // L {0x7F, 0x02, 0x0C, 0x02, 0x7F}, // M {0x7F, 0x04, 0x08, 0x10, 0x7F}, // N {0x3E, 0x41, 0x41, 0x41, 0x3E}, // O {0x7F, 0x09, 0x09, 0x09, 0x06}, // P {0x3E, 0x41, 0x51, 0x21, 0x5E}, // Q {0x7F, 0x09, 0x19, 0x29, 0x46}, // R {0x46, 0x49, 0x49, 0x49, 0x31}, // S {0x01, 0x01, 0x7F, 0x01, 0x01}, // T {0x3F, 0x40, 0x40, 0x40, 0x3F}, // U {0x1F, 0x20, 0x40, 0x20, 0x1F}, // V {0x3F, 0x40, 0x38, 0x40, 0x3F}, // W {0x63, 0x14, 0x08, 0x14, 0x63}, // X {0x07, 0x08, 0x70, 0x08, 0x07}, // Y {0x61, 0x51, 0x49, 0x45, 0x43}, // Z {0x7F, 0x41, 0x41, 0x00, 0x00}, // [ {0x02, 0x04, 0x08, 0x10, 0x20}, // forward slash {0x00, 0x41, 0x41, 0x7F, 0x00}, // ] {0x04, 0x02, 0x01, 0x02, 0x04}, // ^ {0x40, 0x40, 0x40, 0x40, 0x40}, // _ {0x00, 0x01, 0x02, 0x04, 0x00}, // ` {0x20, 0x54, 0x54, 0x54, 0x78}, // a {0x7F, 0x48, 0x44, 0x44, 0x38}, // b {0x38, 0x44, 0x44, 0x44, 0x20}, // c {0x38, 0x44, 0x44, 0x48, 0x7F}, // d {0x38, 0x54, 0x54, 0x54, 0x18}, // e {0x08, 0x7E, 0x09, 0x01, 0x02}, // f {0x0C, 0x52, 0x52, 0x52, 0x3E}, // g {0x7F, 0x08, 0x04, 0x04, 0x78}, // h {0x00, 0x44, 0x7D, 0x40, 0x00}, // i {0x20, 0x40, 0x44, 0x3D, 0x00}, // j {0x7F, 0x10, 0x28, 0x44, 0x00}, // k {0x00, 0x41, 0x7F, 0x40, 0x00}, // l {0x7C, 0x04, 0x18, 0x04, 0x78}, // m {0x7C, 0x08, 0x04, 0x04, 0x78}, // n {0x38, 0x44, 0x44, 0x44, 0x38}, // o {0x7C, 0x14, 0x14, 0x14, 0x08}, // p {0x08, 0x14, 0x14, 0x18, 0x7C}, // q {0x7C, 0x08, 0x04, 0x04, 0x08}, // r {0x48, 0x54, 0x54, 0x54, 0x20}, // s {0x04, 0x3F, 0x44, 0x40, 0x20}, // t {0x3C, 0x40, 0x40, 0x20, 0x7C}, // u {0x1C, 0x20, 0x40, 0x20, 0x1C}, // v {0x3C, 0x40, 0x30, 0x40, 0x3C}, // w {0x44, 0x28, 0x10, 0x28, 0x44}, // x {0x0C, 0x50, 0x50, 0x50, 0x3C}, // y {0x44, 0x64, 0x54, 0x4C, 0x44}, // z }; #endif /* FONT_5X7_H_ */ #include <msp430fr4133.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include "SSD1306.h" #include "i2c.h" #define ANUMBER 19052019 #define MAX_COUNT 4.2e9 #define LONG_DELAY __delay_cycles(3000000) #define SHORT_DELAY __delay_cycles(50000) int main(void) { WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer i2c_init(); // initialize I2C to use with OLED ssd1306_init(); // Initialize SSD1306 OLED ssd1306_clearDisplay(); // Clear OLED display __enable_interrupt(); PMM_unlockLPM5(); while(1) { // ========================================= // Display a Long Text Block // ========================================= // There seems to be a bug in the ssd1306_printTextBlock code, // long text blocks like below need 1 extra character in their array // so the code does not read outside of the array. The below 91 character // text block should only need a array of 92 but to fix the bug use an array of 93. // !!!! MUST FIX BUG IN THE FUTURE !!!! char txtBlock[93] = "This is a long multiline text block. The code will automatically add extra lines as needed."; ssd1306_printTextBlock(0, 1, txtBlock); LONG_DELAY; // Avoid delay loops in real code, use timer ssd1306_clearDisplay(); // ========================================= // Print Single Lines of Text at each row // ========================================= ssd1306_printText(0, 1, "Line 1"); ssd1306_printText(0, 2, "Line 2"); ssd1306_printText(0, 3, "Line 3"); ssd1306_printText(0, 4, "Line 4"); ssd1306_printText(0, 5, "Line 5"); ssd1306_printText(0, 6, "Line 6"); ssd1306_printText(0, 7, "Line 7"); // Print these at a column other then zero ssd1306_printText(40, 1, "40"); ssd1306_printText(50, 2, "50"); ssd1306_printText(60, 3, "60"); ssd1306_printText(70, 4, "70"); ssd1306_printText(80, 5, "80"); ssd1306_printText(90, 6, "90"); ssd1306_printText(100, 7, "100"); // Hold screen for some time before displaying the next sample LONG_DELAY; // Avoid delay loops in real code, use timer ssd1306_clearDisplay(); // ========================================= // Print Unsigned 32 bit number // ========================================= ssd1306_printUI32(0, 1, ANUMBER, HCENTERUL_OFF); // Print number on line 1 ssd1306_printUI32(0, 2, ANUMBER, HCENTERUL_ON); // Print number on line 2, horizontally centered // Print counting on line 6 horizontally centered uint32_t i = 1; uint32_t j; uint32_t val = 0; while (i<1e9) { for(j=0; j<10; j++) { val = i * j; ssd1306_printUI32(0, 6 , val, HCENTERUL_ON); SHORT_DELAY; } i *= 10; } for (j=0; j<5; j++) { val = i * j; ssd1306_printUI32(0, 6 , val, HCENTERUL_ON); SHORT_DELAY; } LONG_DELAY; ssd1306_clearDisplay(); } }我附上了代码供参考。 我认为这个问题可能与 I2C 引脚/中断矢量的配置有关、因为这是我从原始库进行的更改、在 GitHub 上对代码进行了调整。 非常感谢您的任何帮助! 谢谢!