| 在本篇文章中,我们将学习使用STM8S103F3P6开发板上的SPI接口控制8x8图形点阵模块。我们将使用STM8单片机上4个GPIO引脚实现SPI通信,如下图所示。 
  
 所需的组件 ●    STM8S103F3P6开发板 ●    ST-Link烧录器 ●    8x8图形点阵模块MAX7219 ●    连接导线 
 图形点阵模块与STM8S连接的电路图 下图为MAX719图形点阵模模块与STM8S103F3P6开发板的连接图。将模块的DIN引脚与STM8S103F3P6开发板的MOSI引脚连接,CLK连接到STM8S的SCK引脚,CS连接至STM8S的CLK引脚 。使用USB连接器向LCD和单片机提供5V电源。 
  
 STM8S103F3P6上的SPI 在开始介绍STM8S上进行SPI通信之前,您需要确保对SPI通信的工作原理有基本的了解。您需要从Github下载完整的代码文件。转到“T8_SPI_Communication_on_STM8S_using_Cosmic_C_Compiler”文件夹。该文件夹包含两个子文件夹,即“inc”和“src”。我们将使用 Cosmic C 编译器和SPL库。完成项目工作区的设置后,您应该在“Include Files”文件夹下有以下头文件,我在下图中用红色圆圈标记了这些头文件。 
  
 我编写了两个重要的库来简化STM8S上的SPI通信。即“stm8s103_spi.h”和“stm8s_max72xx.h”。如果您想知道图中的其他头文件,可以参考《STM8S 标准外设库》手册。 
 代码 在stm8s103_spi.h文件的开头,我们包含了“STM8S.h”头文件。 “STM8S.h”文件包含“stm8s_spi.h”头文件的定义和STM8S开发板的板卡配置。 SPI 通信的预定义函数可以在“stm8s_spi.h”文件中找到。在“stm8s103_spi.h”中,头文件包含三个SPI通信函数。让我们一一讨论每个函数。 复制代码void delay_ms(int ms) //Function Definition
{
int i =0 ;
int j=0;
for (i=0; i<=ms; i++)
{
for (j=0; j<120; j++) // Nop = Fosc/4
_asm("nop"); //Perform no operation
}
}
delay_ms()函数用于在任务内提供以毫秒为单位的延迟。您可以在 delay_ms() 函数中找到两个嵌套的 for 循环,其中包含另一个函数“_asm(“nop”)”。 _asm(“nop”) 可用于指示微控制器不执行任何操作。 复制代码void SPI_setup(void)
{
     SPI_DeInit();
     SPI_Init(SPI_FIRSTBIT_MSB,
              SPI_BAUDRATEPRESCALER_2,
              SPI_MODE_MASTER,
              SPI_CLOCKPOLARITY_HIGH,
              SPI_CLOCKPHASE_1EDGE,
              SPI_DATADIRECTION_1LINE_TX,
              SPI_NSS_SOFT,
              0x00);
     SPI_Cmd(ENABLE);
}
SPI_setup(void)用于启动SPI通信。该函数对STM8S上的SPI通信具有重要作用。 
 SPI_DeInit() 函数可用于停止开发板上任何先前启动的 SPI 通信。 SPI_Init() 函数用于启动STM8S和从机之间的 SPI 通信。 复制代码void SPI_write(unsigned char slave_address, unsigned char value)
{
    while(SPI_GetFlagStatus(SPI_FLAG_BSY));
    GPIO_WriteLow(CS_port, CS_pin);              
    SPI_SendData(slave_address);
    while(!SPI_GetFlagStatus(SPI_FLAG_TXE));       
    SPI_SendData(value);
    while(!SPI_GetFlagStatus(SPI_FLAG_TXE));               
    GPIO_WriteHigh(CS_port, CS_pin);
}
 SPi_write() 函数可用于将数据写入目标寄存器。首先,我们需要检查SPI状态寄存器是否空闲。我们可以在while循环下使用SPI_GetFlagStatus(SPI_FLAG_BSY)函数来检查SPI通信的状态。 “GPIO_WriteLow(ChipSelect_port, ChipSelect_pin)”函数用于向使用头文件开头的“ChipSelect_port”和“ChipSelect_pin”定义的片选引脚发送‘0’信号。然后“SPI_SendData(slave_address)”用于发送从地址,其中“slave_address”参数包含从设备的目标寄存器的地址。然后我们需要等到传输缓冲区清空,使用“SPI_SendData(value)”发送值,然后需要再次检查传输缓冲区的状态,我们需要等到它为空。现在,我们可以使用“GPIO_WriteHigh(ChipSelect_port, ChipSelect_pin)”将片选引脚设置为高电平。 
 “stm8s_max7xx.h”头文件包含一些函数,可在使用SPI通信将8x8 MAX72xx图形点阵模块与STM8S连接时使用。在这个文件的开头,我为设备寄存器单独定义了一些宏。这些地址可以从 MAX72xx IC 的数据表中找到 复制代码#define decode_mode_reg        0x09
#define intensity_reg                    0x0A
#define scan_limit_reg                                 0x0B
#define shutdown_reg                                0x0C
#define display_test_reg              0x0F
#define shutdown_cmd               0x00
#define run_cmd                           0x01
#define no_test_cmd                   0x00
#define test_cmd                          0x01
alphabets[26]是存储26个字母的char数组。 “alpha_char[26][8]”是一个二维数组,其中包含图形点阵模块的每个字母的八个8 位地址。 
 string_len()函数来获取字符串的长度。MAX7219_init() 函数将MAX7219模块初始化为从设备。在该函数中,可以看到我们将引脚设置成GPIO_MODE_OUT_PP_HIGH_FAST模式。 复制代码void MAX7219_init(void)
{
    GPIO_Init(ChipSelect_port, ChipSelect_pin, GPIO_MODE_OUT_PP_HIGH_FAST);
    SPI_write(shutdown_reg, run_cmd);                
    SPI_write(decode_mode_reg, 0x00);
    SPI_write(scan_limit_reg, 0x07);
    SPI_write(intensity_reg, 0x04);
    SPI_write(display_test_reg, test_cmd);
    delay_ms(10);    
    SPI_write(display_test_reg, no_test_cmd); 
}
 display_string()函数可用于显示字符串。这是一个简单的程序,我使用字符比较将输入字符串的每个字符与字母表的每个字符进行比较。我在“pos”变量中为输入字符串中的每个字符记录了“alphabets”的索引,并将该索引传递给“display_char()”。 复制代码void display_string(const char string[]){                               
    unsigned char j,pos;                              
    int input_string_length  = string_len(string);
                                int alphabets_length  = string_len(alphabets);                               
                for(j=0; j<input_string_length; j++){
                pos = 0;
                while(alphabets[pos]!='\0'){                               
                if(string[j] == alphabets[pos])
                                display_char(pos);               
                pos++; 
                delay_ms(500);
                }
}
}
 在main.c文件中,我们主要有三个函数。即main()、clock_setup() 和GPIO_setup()。在clock_setup() 函数中,我使用了CLK_DeInit() 函数来停止微控制器内任何先前启动的时钟。GPIO_setup()函数中,使用了GPIO_DeInit()函数初始化GPIO,然后通过GPIO_Init()函数初始化了端口C的Pin 5和Pin 6。 复制代码void clock_setup(void)
{
     CLK_DeInit();              
     CLK_HSICmd(ENABLE);
     while(CLK_GetFlagStatus(CLK_FLAG_HSIRDY) == FALSE);
     CLK_ClockSwitchCmd(ENABLE);
     CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
     CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);               
     CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI,
     DISABLE, CLK_CURRENTCLOCKSTATE_ENABLE);         
     CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, ENABLE);
}
void GPIO_setup(void)
{
     GPIO_DeInit(GPIOC);
     GPIO_Init(GPIOC, ((GPIO_Pin_TypeDef)GPIO_PIN_5 | GPIO_PIN_6),
               GPIO_MODE_OUT_PP_HIGH_FAST);
}
 在main()函数中,调用了之前讨论的四个函数。 这些函数可以按照相同的顺序使用,实现在STM8S上建立 SPI 通信。 然后使用display_clear()函数在启动时清空显示。 然后调用“display_char(0)”来显示字母A。 在“while()”循环中,使用display_string()函数来显示字符串。 |