MSCBSC 移动通信论坛
搜索
登录注册
网络优化工程师招聘专栏 4G/LTE通信工程师最新职位列表 通信实习生/应届生招聘职位

  • 阅读:12845
  • 回复:0
【MSP430F5529测评】4. SPI 通信 之 MAX7219 驱动LED点阵
微信Czh6402
中级会员
鎵嬫満鍙风爜宸查獙璇


 发短消息    关注Ta 

积分 530
帖子 106
威望 22182 个
礼品券 0 个
专家指数 0
注册 2020-9-23
专业方向 
回答问题数 0
回答被采纳数 0
回答采纳率 0%
 
发表于 2020-11-12 10:28:10  只看楼主 

MSP430F5529LP SPI 通信测试

这次来测测SPI通信功能,最近买了个MAX7219驱动的LED点阵,恰好也是SPI通信,可以拿来测测。

SPI 通信

首先来看看开发板上引出的SPI接口。


其中完整的SPI接口是P3.0, P3.1 和 P3.2, 分别对应MOSI, MISO,CLK。 MAX7219 作为从设备,只需要接收控制信号,不需要输出数据到板子,所以使用三线制SPI,CS线可以是普通IO,为此我选择的三线SPI是:

  • P3.0 MOSI

  • P3.2 CLK

  • P6.4 CS/LOAD


USCI SPI 模式

UCSI 的 SPI 模式,其控制逻辑如下图所示,里面包含了时钟控制,波特率设定,数据收发,中断等所需的所有寄存器。后续使用寄存器编程可以参考此图。

 


 

 

 

MAX7219 LED 驱动器

接下来看看这个LED点阵屏啥样,8*8的LED单色点阵屏,下面带了个MAX7219 LED驱动器。除了可以驱动点阵屏,还可以驱动7段译码管。单位需要多本通信工程师职称证书挂资质,欢迎联系,陈工15007599549微同

 

这个点阵屏是可以级联的,通过SPI通信,引出5个线,3根控制线,剩下VCC,GND两根线. 对应板子的连线如下:


  • VCC --- 5V

  • GND --- GND

  • DIN  --- P3.0

  • CS  --- P6.4

  • CLK --- P3.2

驱动器包含一些8位寄存器,可以控制驱动器的输出,从而显示想要的点阵。

Digit0 - Digit7 对应8行的灯的输出信号,一个寄存器对应8个灯,上面表格的最右侧是寄存器的地址。给MAX7219 发送数据时,先发送寄存器地址,再发送数据。


  • Decode Mode 设置译码模式

  • Intensity 设置亮度等级(0x00 - 0x0F)

  • Scan limit 设置扫描限制,设置后可以只扫描一部分灯,对于点阵屏自然是全部扫描,所以设置为0x07 (参考手册)

  • Shutdown 使能功能,启用则可以点亮LED

  • Display Test 没试过,应该是用于测试,类似自检

测试

下面来测试下。代码如下,直接看注释,比较简单。

#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 驱动,github 上有很多的开源项目,其中就有一些字库,我参考的是

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

这是现成的字库,不过输出的方向和我的相差个90度,我就自个写了个C程序把它给旋转了。生成后放到font.h , 字库太长就不放了,下面是结合串口通信写的驱动程序。

#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 != '') {send_char(str);i++;}}void flash_led(){uint8_t row, index;for (index = 3; index > 0; index--){// Load all 8 row/digit registers with data from number[index] for (row = 0; row < 8; row++){spi_send(MAX_DIGIT0 + row, number[index][row]);}__delay_cycles(500000); // Wait a bit before showing next frame clear_screen();}__delay_cycles(500000); // Wait a bit before showing next frame for (index = 0; index < 3; index++){// Load all 8 row/digit registers with data from number[index] for (row = 0; row < 8; row++){spi_send(MAX_DIGIT0 + row, iloveu[index][row]);}__delay_cycles(500000); // Wait a bit before showing next frame clear_screen();}__delay_cycles(500000); // Wait a bit before showing next frame for (index = 0; index < 10; index++){spi_send(MAX_DIGIT0 + create_heart[index][0], create_heart[index][1]);__delay_cycles(200000); // Wait a bit before showing next frame }__delay_cycles(500000); // Wait a bit before showing next frame int i = 0;while (i++ < 3){// Loop through some frames for (index = 4; index < 6; index++){// Load all 8 row/digit registers with data from number[index] if (index == 4)spi_send(MAX_INTENSITY, 0x07);else spi_send(MAX_INTENSITY, 0x02);for (row = 0; row < 8; row++){spi_send(MAX_DIGIT0 + row, number[index][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 }void show_char(uint8_t ch){uint8_t row;clear_screen();// Load all 8 row/digit registers with data from ASCII_FONTS[ch] for (row = 0; row < 8; row++){spi_send(MAX_DIGIT0 + row, ASCII_FONTS[ch][row]);}}uint8_t chr = 0;int main(void){WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer // USCI_A1 UART P4SEL |= BIT4+BIT5;                       // P4.4,5 = USCI_A1 TXD/RXD UCA1CTL1 |= UCSWRST;                      // **Put state machine in reset** UCA1CTL1 |= UCSSEL_2;                     // SMCLK UCA1BR0 = 9;                              // 1MHz 115200 (see User's Guide) UCA1BR1 = 0;                              // 1MHz 115200 UCA1MCTL |= UCBRS_1 + UCBRF_0;            // Modulation UCBRSx=1, UCBRFx=0 UCA1CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine** UCA1IE |= UCRXIE;                         // Enable USCI_A1 RX interrupt // MAX7219 SPI 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);__bis_SR_register( GIE);                   // interrupts enabled init_MAX7219();__delay_cycles(1000);flash_led();uint8_t old_chr = 0;while(1) {//        __bis_SR_register(LPM0_bits); if (old_chr != chr) {show_char(chr);old_chr = chr;}__delay_cycles(1000);}}// Echo back RXed character, confirm TX buffer is ready first #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector=USCI_A1_VECTOR __interrupt void USCI_A1_ISR(void)#elif defined(__GNUC__) void __attribute__ ((interrupt(USCI_A1_VECTOR))) USCI_A1_ISR (void)#else #error Compiler not supported! #endif {switch(__even_in_range(UCA1IV,4)){case 0:break;                             // Vector 0 - no interrupt case 2:                                   // Vector 2 - RXIFG while (!(UCA1IFG&UCTXIFG));             // USCI_A1 TX buffer ready? chr = UCA1RXBUF;UCA1TXBUF = chr;                        // TX -> RXed character //    __bic_SR_register_on_exit(LPM0_bits); break;case 4:break;                             // Vector 4 - TXIFG default: break;}}

 

在UART中断中把接收到的字符存在buf中,主循环去判断是否有更新,如果有就驱动LED更新显示。

比如,咱显示个大写字母Q


哈哈,是不是很有趣,其实可以搞些好玩的动画,横屏或者竖屏滚动,或者旋转,然后配合时间控制以及亮度调节,会更好玩。时间有限就先这样吧。

参考资料

  • https://github.com/evilbetty/msp430_max7219_ledmatrix

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

 MAX7219-MAX7221_cn.pdf (1.35 MB, 下载次数: 0)


此帖出自微控制器 MCU论坛


扫码关注5G通信官方公众号,免费领取以下5G精品资料
  • 1、回复“YD5GAI”免费领取《中国移动:5G网络AI应用典型场景技术解决方案白皮书
  • 2、回复“5G6G”免费领取《5G_6G毫米波测试技术白皮书-2022_03-21
  • 3、回复“YD6G”免费领取《中国移动:6G至简无线接入网白皮书
  • 4、回复“LTBPS”免费领取《《中国联通5G终端白皮书》
  • 5、回复“ZGDX”免费领取《中国电信5G NTN技术白皮书
  • 6、回复“TXSB”免费领取《通信设备安装工程施工工艺图解
  • 7、回复“YDSL”免费领取《中国移动算力并网白皮书
  • 8、回复“5GX3”免费领取《 R16 23501-g60 5G的系统架构1
  • 对本帖内容的看法? 我要点评

     
    [充值威望,立即自动到帐] [VIP贵宾权限+威望套餐] 另有大量优惠赠送活动,请光临充值中心
    充值拥有大量的威望和最高的下载权限,下载站内资料无忧

    快速回复主题    
    标题
    内容
     上传资料请点左侧【添加附件】

    当前时区 GMT+8, 现在时间是 2026-06-27 05:22:57
    渝ICP备11001752号  Copyright @ 2006-2016 mscbsc.com  本站统一服务邮箱:mscbsc@163.com

    Processed in 0.897575 second(s), 13 queries , Gzip enabled
    TOP
    清除 Cookies - 联系我们 - 移动通信网 - 移动通信论坛 - 通信招聘网 - Archiver