MSCBSC 移動通信論壇
搜索
登錄注冊
網(wǎng)絡(luò)優(yōu)化工程師招聘專欄 4G/LTE通信工程師最新職位列表 通信實習(xí)生/應(yīng)屆生招聘職位

  • 閱讀:12654
  • 回復(fù):0
【MSP430F5529測評】4. SPI 通信 之 MAX7219 驅(qū)動LED點陣
微信Czh6402
中級會員
鎵嬫満鍙風(fēng)爜宸查獙璇? style=


 發(fā)短消息    關(guān)注Ta 

積分 530
帖子 106
威望 21132 個
禮品券 0 個
專家指數(shù) 0
注冊 2020-9-23
專業(yè)方向 
回答問題數(shù) 0
回答被采納數(shù) 0
回答采納率 0%
 
發(fā)表于 2020-11-12 10:28:10  只看樓主 

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 上有很多的開源項目,其中就有一些字庫,我參考的是

  • https://github.com/riyas-org/max7219/blob/master/max7219-rpi/src/font.py

這是現(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 != '