在STM8S板上执行SPI通信的教程

在STM8S板上执行SPI通信的教程,第1张

  在本教程中,我们将了解 使用 8x8 Led 矩阵显示模块 作为 SPI 设备在 STM8S103F3P6 板上实现串行并行接口 (SPI) 通信。我们将使用 4 个 GPIO 引脚来执行 SPI 通信,如下图所示。那么,让我们看看在 STM8S 板上执行 SPI 通信需要哪些组件。您可以查看我们 关于 STM8S 微控制器的教程,其中我们讨论了如何设置 Cosmic C 编译器,并且我们已经使用 STM8S103F3P6 开发板介绍了 PWM、ADCUARTI2C

在STM8S板上执行SPI通信的教程,poYBAGLjkoSAQI6lAAGf4yE-guA341.png,第2张

  所需组件

  我们将需要以下组件在 STM8S 上使用 MLX90614 I2C 传感器执行 I2C 通信。

  STM8S103F3P6开发板

  ST-Link V2 编程器

  8x8 MAX7219 LED 矩阵显示模块。

  连接线

  使用 SPI 将点阵显示模块与 STM8S 连接的电路

  下图为 MAX719 点阵显示模块与 STM8S103F3P6 开发板的连接图。我已将模块的 DIN 引脚与 STM8S103F3P6 板的 SDA (PB5) 和 SCL(PB4) 引脚连接起来。我还为传感器和 LCD 提供了 5V 电源。请注意,我们需要使用 USB 连接器为 STM8S103F3P6 板供电,以便板为传感器和 LCD 提供适当的 5V 电源。

在STM8S板上执行SPI通信的教程,pYYBAGLjkomATxkwAAFN5KHCQxU946.png,第3张

  STM8S103F3P6 上的 SPI

  在开始使用 STM8S 上的 SPI 通信之前,您需要确保您对 SPI 通信的工作原理有基本的了解。到目前为止,我们已经介绍了与不同类型微控制器的SPI 通信。所以,我不打算讨论 SPI 通信的理论部分。您需要从我们的 STM8S 教程系列的 GITHUB 存储库中下载完整的代码文件。转到可以在下载的存储库中找到的“T8_SPI_CommunicaTIon_on_STM8S_using_Cosmic_C_Compiler”文件夹。此文件夹包含两个子文件夹,即。 “inc”和“src”。 我们将使用 Cosmic C 编译器和 SPL 库。我希望您已经阅读了我们关于 STM8S 的第一个教程,我们在其中讨论了如何设置项目工作区。完成项目工作区的设置后,在下图中我用红色圆圈标记的“包含文件”文件夹下应该有以下头文件。在STM8S的第一个教程中,我们已经讨论了如何添加包含文件(可以在“ inc ”文件夹中找到)和源文件(可以在“ src ”文件夹中找到)。

在STM8S板上执行SPI通信的教程,pYYBAGLjko-Afm3KAAGAYYP07wc253.png,第4张

  现在,让我们看看库里面有什么。我创建了两个重要的库来简化 STM8S 上的 SPI 通信。即“ stm8s103_spi.h ”和“ stm8s_max72xx.h ”。您可能想知道图片中的其他头文件。可以参考《STM8S 标准外设库》手册。现在,让我们进入编码部分。

  在stm8s103_spi.h头文件里面:

在 stm8s103_spi.h 文件的开头,我们包含了“ STM8S.h ”头文件。“ STM8S.h ”文件包含“ stm8s_spi.h ”头文件的定义和STM8S开发板的板配置。SPI 通信的预定义函数可以在“ stm8s_spi.h ”文件中找到。我们不讨论stm8s_spi.h头文件中的每个函数,而是讨论“stm8s103_spi.h”头文件中使用的重要函数。在“stm8s103_spi.h”中,头文件包含三个用于SPI通信的函数。让我们一一讨论每个功能。

 

void delay_ms(int ms) //函数定义
{
整数 i =0 ;
诠释 j = 0;
对于 (i=0; i<=ms; i++)
{
for (j=0; j<120; j++) // Nop = Fosc/4
_asm("nop"); //不执行任何操作
}
}

 

上面提到的函数“delay_ms()”用于在任务中提供以毫秒为单位的延迟。您可以在delay_ms()函数中找到两个嵌套的 for 循环,其中包含另一个函数“_asm(“nop”)”。_asm(“nop”)可用于指示微控制器不执行任何 *** 作。此delay_ms()函数可以将一个参数作为整数,以毫秒为单位表示延迟。

 

无效SPI_setup(无效)
{
     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(启用);
}

 

  上面提到的下一个函数“ SPI_setup(void)”是一个不可返回的函数,可以用来启动SPI通信。该函数对STM8S上的SPI通信有重要作用。在讨论这个函数之前,让我告诉你这个函数可以在stm8s_spi.h头文件中找到。您可以简单地右键单击每个功能,然后您需要单击“转到定义”选项,该选项可以在您按右键单击该功能后在d出窗口中找到。你可以参考下图。

在STM8S板上执行SPI通信的教程,pYYBAGLjkpaAYNlFAAG4RaUUkZE445.png,第5张

  SPI_DeInit ()函数可用于停止板上任何先前启动的 SPI 通信。SPI_Init ()函数用于启动 Board 和 Slave 之间的 SPI 通信。这个初始化函数有一些参数需要处理。您可以按照与上述相同的方法转到每个参数的定义。我们应该感谢“ stm8s_spi.h ”头文件的创建者,因为他们在注释中提到了文件中的每个细节。我想通过阅读这些注释,您将很容易理解这些函数中使用的每个参数。我们可以使用SPI_Cmd()函数启用或禁用 SPI 外设。

 

void SPI_write(unsigned char slave_address, unsigned char value)
{
    而(SPI_GetFlagStatus(SPI_FLAG_BSY));
    GPIO_WriteLow(CS_port,CS_pin);              
    SPI_SendData(slave_address);
    而(!SPI_GetFlagStatus(SPI_FLAG_TXE));       
    SPI_SendData(值);
    而(!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 上执行 SPI 时可能会遇到一些错误。我已经提到了我在执行此 *** 作时遇到的错误。IE

“while(!SPI_GetFlagStatus(SPI_FLAG_TXE))”循环永远不会中断。这意味着发送缓冲区不为空。您可以使用“ SPI_SendData() ”函数检查您发送的地址位。或者您可以检查您的接线设置,如果所有电线都正确连接。

在stm8s_max72xx.h头文件里面:

“ stm8s_max7xx.h”头文件有一些功能,可在使用 SPI 通信将 8x8 MAX72xx Led 矩阵显示板与 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]”是一个二维 (2D) 数组,其中包含 8x8 Led 矩阵的每个字母表的八个 8 位地址。例如,让我们查看“ alpha_char”的第 0个索引,我们有 8 个 8 位十六进制数据。此十六进制数据表示 8x8 矩阵格式中的字母“A”。

 

const char 字母[26]= "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const uint8_t alpha_char[26][8] = {{0x0, 0xfc, 0xfe, 0x27, 0x27, 0xfe, 0xfc, 0x0},
{0x0, 0xfe, 0xfe, 0x92, 0x92, 0xfe, 0x6c, 0x0},
{0x0, 0x7e, 0xff, 0xc3, 0xc3, 0xe7, 0x66, 0x0},
{0x0, 0xff, 0xff, 0xc3, 0xc3, 0xff, 0x7e, 0x0},
{0x0, 0xfe, 0xfe, 0x92, 0xba, 0x82, 0xc6, 0x0},
{0x82, 0xfe, 0xfe, 0x92, 0x3a, 0x2, 0x6, 0x0},
{0x0, 0x7e, 0xff, 0xc3, 0xd3, 0xf7, 0x76, 0x0},
{0x0, 0xfe, 0xfe, 0x30, 0x30, 0xfe, 0xfe, 0x0},
{0x0, 0xc6, 0xc6, 0xfe, 0xfe, 0xc6, 0xc6, 0x0},
{0x0, 0x30, 0x70, 0x63, 0x63, 0x7f, 0x3f, 0x3},
{0x0, 0xff, 0xff, 0x18, 0x3c, 0x6e, 0xc7, 0x0},
{0x0, 0x81, 0xff, 0xff, 0x81, 0x80, 0xe0, 0x0},
{0x0, 0xfe, 0xfe, 0x1c, 0x38, 0x1c, 0xfe, 0xfe},
{0x4e, 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6},
{0x4f, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38},
{0x50, 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0},
{0x51, 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c},
{0x0, 0xff, 0xff, 0x33, 0x33, 0xff, 0xee, 0xc0},
{0x0, 0xce, 0xdf, 0xdb, 0xdb, 0xfb, 0x73, 0x0},
{0x0, 0x7, 0x83, 0xff, 0xff, 0x83, 0x7, 0x0},
{0x0, 0x7f, 0xff, 0xc0, 0xc0, 0xff, 0x7f, 0x0},
{0x56, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30},
{0x57, 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6},
{0x58, 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6},
{0x59, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78},
{0x7f, 0x7f, 0x61, 0x31, 0x98, 0x8c, 0xfe, 0xfe}
};

 

然后我们有一个“ string_len()”函数来获取字符串的长度。我创建了一个MAX7219_init()函数来将 MAX7219 LED 矩阵初始化为从设备。在这个函数中,你可以看到我已经在“ GPIO_MODE_OUT_PP_HIGH_FAST ”模式下初始化了“ChipSelect_port”和“ChipSelect_pin”。我们需要按照数据表使用该寄存器命令来初始化 MAX7219。我调用了“SPI_write()”函数将数据写入我在头文件顶部定义的电阻器中。

 

无效 MAX7219_init(无效)
{
    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);
    延迟毫秒(10);    
    SPI_write(display_test_reg, no_test_cmd);
}

 

下面提到的“display_clear(void)”函数用于清除 LED 矩阵。我在“zeros_clr[8]”数组中使用了 8 个 8 位 0 。然后我在 for 循环中使用该数组的每一位将 8x8 LED 矩阵显示器的每个 LED 设置为'0'或'LOW'。

 

无效显示清除(无效){
                    无符号字符 zeros_clr[8] = {0x00、0x00、0x00、0x00、0x00、0x00、0x00、0x00};
 无符号字符 j = 0x00;               
                for(j = 0; j < sizeof(zeros_clr); j++)
                {                                              
                                                SPI_write((1 + j), zeros_clr [j]);
                                                延迟毫秒(100);
                }
}

 

“ display_char(int alphabet_sequence)”可用于在 LED 矩阵显示板上显示字符。我们需要提供“alpha_char[][]”数组的字母索引。在函数内部,我们有“SPI_write()”。这次我们提供了 Led 矩阵的行和列的寄存器值,以将数据写入特定的 LED。

 

void display_char (int alphabet_sequence)
{
                  无符号整数 i;
                                for(i=0; i<8; i++){
                SPI_write((i+1), alpha_char[alphabet_sequence][i]);
                                                             延迟毫秒(100);                              
                                }
}

 

“ display_string()”可用于显示字符串。这是一个简单的程序,我使用字符比较来将输入字符串的每个字符与“字母”的每个字符进行比较。我为输入字符串中的每个字符记录了“pos”变量中“ alphabets ”的索引,并将该索引传递给“display_char()”。

 

void display_string (const char string[]){                               
    无符号字符 j,pos;                              
    int input_string_length = string_len(string);
                                int alphabets_length = string_len(字母);                               
                for(j=0;j

 

在 main.c 文件中:

现在,我们有了要讨论的main.c文件。在main.c文件中,我们有三个函数。即main()、clock_setup()和GPIO_setup()。在clock_setup()函数中,我使用了CLK_DeInit()函数来停止微控制器内部任何先前启动的CPU。您可以轻松获得此处使用的每个函数和参数的详细说明。您需要使用我之前讨论过的“转到定义”方法。在GPIO_setup() 中,我使用GPIO_DeInit()函数去初始化端口 C。然后我初始化了端口 C 的 Pin 5 和 Pin 6 。 通过使用GPIO_Init()函数。

 

无效时钟设置(无效)
{
     CLK_DeInit();              
     CLK_HSICmd(启用);
     而(CLK_GetFlagStatus(CLK_FLAG_HSIRDY) == FALSE);
     CLK_ClockSwitchCmd(启用);
     CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
     CLK_SYSCLKConfig(CLK_PRESCALER_DIV1);               
     CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI,
     禁用,CLK_CURRENTCLOCKSTATE_ENABLE);         
     CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, ENABLE);
}
无效 GPIO_setup(无效)
{
     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()”函数在启动时清除显示。然后我用参数“0”调用“ display_char() ”来显示字母“A”。在“while()”循环中,我使用“display_string()”和“display_clear()”函数来显示字符串。就我而言,我使用“ CIRCUITDIGEST ”作为字符串显示在 Led 矩阵显示器上。它将每隔 2 秒显示一次该字符串。

  至此,我们终于在STM8S103F3P6开发板上完成了SPI通信。

    #include “STM8S.h”

  #include “stm8s103_SPI.h”

  #include “stm8s_max72xx.h”

  void clock_setup(void);

  无效 GPIO_setup(无效);

  void main()

  {

  const char input_string2[] = “CIRCUITDIGEST”;

  时钟设置();

  GPIO_setup();

  SPI_setup();

  MAX7219_init();

  显示清除();//清除显示

  delay_ms(1000);

  显示字符(0);// 显示字母“A”

  delay_ms(4000);

  while(TRUE)

  {

  display_clear(); //清除显示

  display_string(input_string2);

  };

  }

  void clock_setup(void)

  {

  CLK_DeInit();

  CLK_HSICmd(启用);

  而(CLK_GetFlagStatus(CLK_FLAG_HSIRDY) == FALSE);

  CLK_ClockSwitchCmd(启用);

  CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);

  CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);

  CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO,CLK_SOURCE_HSI,

  禁用,CLK_CURRENTCLOCKSTATE_ENABLE);

  CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, ENABLE);

  }

  无效 GPIO_setup(void)

  {

  GPIO_DeInit(GPIOC);

  GPIO_Init(GPIOC, ((GPIO_Pin_TypeDef)GPIO_PIN_5 | GPIO_PIN_6),

  GPIO_MODE_OUT_PP_HIGH_FAST);

  }

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/dianzi/2711171.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-08-17
下一篇2022-08-17

发表评论

登录后才能评论

评论列表(0条)

    保存