MSP430F5529LP SPI 通信測試
這次來測測SPI通信功能,最近買了個MAX7219驅(qū)動的LED點陣,恰好也是SPI通信,可以拿來測測。
SPI 通信
首先來看看開發(fā)板上引出的SPI接口。
其中完整的SPI接口是P3.0, P3.1 和 P3.2, 分別對應(yīng)MOSI, MISO,CLK。 MAX7219 作為從設(shè)備,只需要接收控制信號,不需要輸出數(shù)據(jù)到板子,所以使用三線制SPI,CS線可以是普通IO,為此我選擇的三線SPI是:
P3.0 MOSI
P3.2 CLK
P6.4 CS/LOAD
USCI SPI 模式
UCSI 的 SPI 模式,其控制邏輯如下圖所示,里面包含了時鐘控制,波特率設(shè)定,數(shù)據(jù)收發(fā),中斷等所需的所有寄存器。后續(xù)使用寄存器編程可以參考此圖。
MAX7219 LED 驅(qū)動器
接下來看看這個LED點陣屏啥樣,8*8的LED單色點陣屏,下面帶了個MAX7219 LED驅(qū)動器。除了可以驅(qū)動點陣屏,還可以驅(qū)動7段譯碼管。單位需要多本通信工程師職稱證書掛資質(zhì),歡迎聯(lián)系,陳工15007599549微同
這個點陣屏是可以級聯(lián)的,通過SPI通信,引出5個線,3根控制線,剩下VCC,GND兩根線. 對應(yīng)板子的連線如下:
VCC --- 5V
GND --- GND
DIN --- P3.0
CS --- P6.4
CLK --- P3.2
驅(qū)動器包含一些8位寄存器,可以控制驅(qū)動器的輸出,從而顯示想要的點陣。
Digit0 - Digit7 對應(yīng)8行的燈的輸出信號,一個寄存器對應(yīng)8個燈,上面表格的最右側(cè)是寄存器的地址。給MAX7219 發(fā)送數(shù)據(jù)時,先發(fā)送寄存器地址,再發(fā)送數(shù)據(jù)。
Decode Mode 設(shè)置譯碼模式
Intensity 設(shè)置亮度等級(0x00 - 0x0F)
Scan limit 設(shè)置掃描限制,設(shè)置后可以只掃描一部分燈,對于點陣屏自然是全部掃描,所以設(shè)置為0x07 (參考手冊)
Shutdown 使能功能,啟用則可以點亮LED
Display Test 沒試過,應(yīng)該是用于測試,類似自檢
測試
下面來測試下。代碼如下,直接看注釋,比較簡單。
#include <msp430.h> #include <stdint.h> void spi_send(uint8_t address, uint8_t data);void init_MAX7219(void);// MAX7219 Register addresses #define MAX_NOOP 0x00 #define MAX_DIGIT0 0x01 #define MAX_DIGIT1 0x02 #define MAX_DIGIT2 0x03 #define MAX_DIGIT3 0x04 #define MAX_DIGIT4 0x05 #define MAX_DIGIT5 0x06 #define MAX_DIGIT6 0x07 #define MAX_DIGIT7 0x08 #define MAX_DECODEMODE 0x09 #define MAX_INTENSITY 0x0A #define MAX_SCANLIMIT 0x0B #define MAX_SHUTDOWN 0x0C #define MAX_DISPLAYTEST 0x0F // 8x8 number font const uint8_t number[][8] = { {0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c}, // 0 {0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c}, // 1 {0x3c, 0x66, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x7e}, // 2 {0x3c, 0x66, 0x06, 0x1e, 0x1e, 0x06, 0x66, 0x3c}, // 3 {0x66, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00}, // heart-full // {0x66, 0xDB, 0x81, 0x81, 0x42, 0x24, 0x18, 0x00}, // heart-empty // {0x00, 0x24, 0x7E, 0x7E, 0x3C, 0x18, 0x00, 0x00}, // small heart {0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18}, // heart-full };const uint8_t iloveu[][8] = { {0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E}, // I {0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18}, // love, heart-full {0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18}, // U };const uint8_t create_heart[10][2] = { // row, value {0, 0x00}, {2, 0x18}, {1, 0x24}, {1, 0x66}, {2, 0x99}, {3, 0x81}, {4, 0x81}, {5, 0x42}, {6, 0x24}, {7, 0x18},};uint8_t returnValue_SPI = 0x00;uint8_t row, framecounter;void clear_screen() { int row; for (row = 0; row < 8; row++) { spi_send(MAX_DIGIT0 + row, 0x00); } __delay_cycles(500000); // Wait a bit before showing next frame }int main(void){ WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer P6OUT |= BIT4; // Set P6.4 for CS P6DIR |= BIT4; // Set P6.4 to output direction P3SEL |= BIT0 + BIT2; // P3.0,2 option select //P3DIR |= BIT0+BIT1+BIT2; // Set P3.0,2 to output direction UCB0CTL1 |= UCSWRST; // **Put state machine in reset** UCB0CTL0 |= UCMST + UCCKPH + UCMSB + UCSYNC; // 3-pin, 8-bit SPI master // MSB UCB0CTL1 |= UCSSEL_2; // SMCLK UCB0BR0 = 0x02; // /2 UCB0BR1 = 0; // UCB0CTL1 &= ~UCSWRST; // Initialize USCI state machine __delay_cycles(100000); init_MAX7219(); __delay_cycles(1000); uint8_t row, framecounter; for (framecounter = 3; framecounter > 0; framecounter--) { // Load all 8 row/digit registers with data from number[framecounter] for (row = 0; row < 8; row++) { spi_send(MAX_DIGIT0 + row, number[framecounter][row]); } __delay_cycles(500000); // Wait a bit before showing next frame clear_screen(); } for (framecounter = 0; framecounter < 3; framecounter++) { // Load all 8 row/digit registers with data from number[framecounter] for (row = 0; row < 8; row++) { spi_send(MAX_DIGIT0 + row, iloveu[framecounter][row]); } __delay_cycles(500000); // Wait a bit before showing next frame clear_screen(); } for (framecounter = 0; framecounter < 10; framecounter++) { spi_send(MAX_DIGIT0 + create_heart[framecounter][0], create_heart[framecounter][1]); __delay_cycles(200000); // Wait a bit before showing next frame } while (1) { // Loop through some frames for (framecounter = 4; framecounter < 6; framecounter++) { // Load all 8 row/digit registers with data from number[framecounter] if (framecounter == 4) spi_send(MAX_INTENSITY, 0x07); else spi_send(MAX_INTENSITY, 0x02); for (row = 0; row < 8; row++) { spi_send(MAX_DIGIT0 + row, number[framecounter][row]); } __delay_cycles(400000); // Wait a bit before showing next frame } }}// Send 16 bits as: xxxxaaaadddddddd (ignore, address, data) // and use active low Chip Select void spi_send(uint8_t address, uint8_t data){ P6OUT &= ~BIT4; // CS low _delay_cycles(50); while (!(UCB0IFG & UCTXIFG)){} // Wait until done UCB0TXBUF = (address & 0x0F); while (!(UCB0IFG & UCTXIFG)){} // Wait until done UCB0TXBUF = (data); while (!(UCB0IFG & UCTXIFG)){} // Wait until done P6OUT |= BIT4; // CS high }void init_MAX7219(void){ // Initialise MAX7219 with 8x8 led matrix spi_send(MAX_NOOP, 0x00); // NO OP (seems needed after power on) spi_send(MAX_SCANLIMIT, 0x07); // Enable all digits (always needed for current/8 per row) spi_send(MAX_INTENSITY, 0x03); // Display intensity (0x00 to 0x0F) spi_send(MAX_DECODEMODE, 0); // No BCD decoding for led matrix // Clear all rows/digits spi_send(MAX_DIGIT0, 0); spi_send(MAX_DIGIT1, 0); spi_send(MAX_DIGIT2, 0); spi_send(MAX_DIGIT3, 0); spi_send(MAX_DIGIT4, 0); spi_send(MAX_DIGIT5, 0); spi_send(MAX_DIGIT6, 0); spi_send(MAX_DIGIT7, 0); spi_send(MAX_SHUTDOWN, 1); // Wake oscillators/display up }
這個例子是顯示I love U, love是個愛心桃,哈哈,給女朋友瞅瞅
串口控制LED輸出
接下來再加點東西,把之前用的串口拿過來用用,通過串口控制LED的顯示,不過這里要提到一個取模,上面實際上也用到了,取模軟件比較多,就不推薦了。
針對MAX7219 驅(qū)動,github 上有很多的開源項目,其中就有一些字庫,我參考的是
這是現(xiàn)成的字庫,不過輸出的方向和我的相差個90度,我就自個寫了個C程序把它給旋轉(zhuǎn)了。生成后放到font.h , 字庫太長就不放了,下面是結(jié)合串口通信寫的驅(qū)動程序。
#include <msp430.h> #include <stdint.h> #include <stdio.h> #include <string.h> #include "font.h" void spi_send(uint8_t address, uint8_t data);void init_MAX7219(void);// MAX7219 Register addresses #define MAX_NOOP 0x00 #define MAX_DIGIT0 0x01 #define MAX_DIGIT1 0x02 #define MAX_DIGIT2 0x03 #define MAX_DIGIT3 0x04 #define MAX_DIGIT4 0x05 #define MAX_DIGIT5 0x06 #define MAX_DIGIT6 0x07 #define MAX_DIGIT7 0x08 #define MAX_DECODEMODE 0x09 #define MAX_INTENSITY 0x0A #define MAX_SCANLIMIT 0x0B #define MAX_SHUTDOWN 0x0C #define MAX_DISPLAYTEST 0x0F // 8x8 number font const uint8_t number[][8] = {{0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c}, // 0 {0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c}, // 1 {0x3c, 0x66, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x7e}, // 2 {0x3c, 0x66, 0x06, 0x1e, 0x1e, 0x06, 0x66, 0x3c}, // 3 {0x66, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00}, // heart-full {0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18}, // heart-full };const uint8_t iloveu[][8] = {{0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E}, // I {0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18}, // love, heart-full {0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18}, // U };const uint8_t create_heart[10][2] = {// row, value {0, 0x00},{2, 0x18},{1, 0x24},{1, 0x66},{2, 0x99},{3, 0x81},{4, 0x81},{5, 0x42},{6, 0x24},{7, 0x18},};void clear_screen() {int row;for (row = 0; row < 8; row++){spi_send(MAX_DIGIT0 + row, 0x00);}}// UART send char void send_char(char c){while (!(UCA1IFG&UCTXIFG)); // USCI_A1 TX buffer ready? UCA1TXBUF = c;}void send_strings(char *str){unsigned int i = 0;while(str != '