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

在本教程中,我们将了解 使用 8x8 led 矩阵显示模块 作为 spi 设备在 stm8s103f3p6 板上实现串行并行接口 (spi) 通信。我们将使用 4 个 gpio 引脚来执行 spi 通信,如下图所示。那么,让我们看看在 stm8s 板上执行 spi 通信需要哪些组件。您可以查看我们 关于 stm8s 微控制器的教程,其中我们讨论了如何设置 cosmic c 编译器,并且我们已经使用 stm8s103f3p6 开发板介绍了 pwm、adc、uart 和 i2c。
所需组件
我们将需要以下组件在 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 电源。
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 通信。即“ 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头文件中找到。您可以简单地右键单击每个功能,然后您需要单击“转到定义”选项,该选项可以在您按右键单击该功能后在弹出窗口中找到。你可以参考下图。
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()函数来停止微控制器内部任何先前启动的时钟。您可以轻松获得此处使用的每个函数和参数的详细说明。您需要使用我之前讨论过的“转到定义”方法。在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_cpudiv1); 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);
}

沃兹用阴郁的色调描述了他对未来的展望
混合云有什么好处?
什么是太阳能蓄电池
iOS13值不值得升级
英特尔Fortran编译器的优势特点介绍
在STM8S板上执行SPI通信的教程
一种新的“多度仪”可配对手持式CMOS传感器以及基于Android的智能手机或平板电脑应用程序
Galaxy Z Fold 2在Galaxy Fold的基础上增加了很多改进
15分钟参透比特币和区块链
小米MIX2有了危机感 华为荣耀畅玩7X让高端全面屏只卖平民价
湘江实验室成立,拓维信息成为首批共建单位
粤港澳大湾区高质量供电可靠性指标持续领跑全国
“各类传感器已经足够出色,更需要的是提升处理能力”
5G从空中落实到地上
让云无处不在,让智能无所不及---华为云共建智能世界云底座
逆变器买多大合适
车用模拟IC和分离式功率器件的重要性越发明显
Windows 10未来或自动向用户推送驱动更新 厂商可快速了解和确认驱动问题
基于STM32F407的网络化智能车灯控制系统
机智云10年力证 物联网平台始于方案演化