在本教程中,我們將了解 使用 8x8 Led 矩陣顯示模塊 作為 SPI 設備在 STM8S103F3P6 板上實現(xiàn)串行并行接口 (SPI) 通信。我們將使用 4 個 GPIO 引腳來執(zhí)行 SPI 通信,如下圖所示。那么,讓我們看看在 STM8S 板上執(zhí)行 SPI 通信需要哪些組件。您可以查看我們 關于 STM8S 微控制器的教程,其中我們討論了如何設置 Cosmic C 編譯器,并且我們已經使用 STM8S103F3P6 開發(fā)板介紹了 PWM、ADC、UART 和 I2C。
所需組件
我們將需要以下組件在 STM8S 上使用 MLX90614 I2C 傳感器執(zhí)行 I2C 通信。
STM8S103F3P6開發(fā)板
ST-Link V2 編程器
8x8 MAX7219 LED 矩陣顯示模塊。
連接線
使用 SPI 將點陣顯示模塊與 STM8S 連接的電路圖
下圖為 MAX719 點陣顯示模塊與 STM8S103F3P6 開發(fā)板的連接圖。我已將模塊的 DIN 引腳與 STM8S103F3P6 板的 SDA (PB5) 和 SCL(PB4) 引腳連接起來。我還為傳感器和 LCD 提供了 5V 電源。請注意,我們需要使用 USB 連接器為 STM8S103F3P6 板供電,以便板為傳感器和 LCD 提供適當?shù)?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 的第一個教程,我們在其中討論了如何設置項目工作區(qū)。完成項目工作區(qū)的設置后,在下圖中我用紅色圓圈標記的“包含文件”文件夾下應該有以下頭文件。在STM8S的第一個教程中,我們已經討論了如何添加包含文件(可以在“ inc ”文件夾中找到)和源文件(可以在“ src ”文件夾中找到)。
現(xiàn)在,讓我們看看庫里面有什么。我創(chuàng)建了兩個重要的庫來簡化 STM8S 上的 SPI 通信。即“ stm8s103_spi.h ”和“ stm8s_max72xx.h ”。您可能想知道圖片中的其他頭文件??梢詤⒖肌禨TM8S 標準外設庫》手冊。現(xiàn)在,讓我們進入編碼部分。
在stm8s103_spi.h頭文件里面:
在 stm8s103_spi.h 文件的開頭,我們包含了“?STM8S.h?”頭文件。“?STM8S.h?”文件包含“?stm8s_spi.h?”頭文件的定義和STM8S開發(fā)板的板配置。SPI 通信的預定義函數(shù)可以在“?stm8s_spi.h?”文件中找到。我們不討論stm8s_spi.h頭文件中的每個函數(shù),而是討論“stm8s103_spi.h”頭文件中使用的重要函數(shù)。在“stm8s103_spi.h”中,頭文件包含三個用于SPI通信的函數(shù)。讓我們一一討論每個功能。
?
void delay_ms(int ms) //函數(shù)定義 { 整數(shù) i =0 ; 詮釋 j = 0; 對于 (i=0; i<=ms; i++) { for (j=0; j<120; j++) // Nop = Fosc/4 _asm("nop"); //不執(zhí)行任何操作 } }
?
上面提到的函數(shù)“delay_ms()”用于在任務中提供以毫秒為單位的延遲。您可以在delay_ms()函數(shù)中找到兩個嵌套的 for 循環(huán),其中包含另一個函數(shù)“_asm(“nop”)”。_asm(“nop”)可用于指示微控制器不執(zhí)行任何操作。此delay_ms()函數(shù)可以將一個參數(shù)作為整數(shù),以毫秒為單位表示延遲。
?
無效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(啟用); }
?
上面提到的下一個函數(shù)“ SPI_setup(void)”是一個不可返回的函數(shù),可以用來啟動SPI通信。該函數(shù)對STM8S上的SPI通信有重要作用。在討論這個函數(shù)之前,讓我告訴你這個函數(shù)可以在stm8s_spi.h頭文件中找到。您可以簡單地右鍵單擊每個功能,然后您需要單擊“轉到定義”選項,該選項可以在您按右鍵單擊該功能后在彈出窗口中找到。你可以參考下圖。
SPI_DeInit?()函數(shù)可用于停止板上任何先前啟動的 SPI 通信。SPI_Init?()函數(shù)用于啟動 Board 和 Slave 之間的 SPI 通信。這個初始化函數(shù)有一些參數(shù)需要處理。您可以按照與上述相同的方法轉到每個參數(shù)的定義。我們應該感謝“?stm8s_spi.h?”頭文件的創(chuàng)建者,因為他們在注釋中提到了文件中的每個細節(jié)。我想通過閱讀這些注釋,您將很容易理解這些函數(shù)中使用的每個參數(shù)。我們可以使用SPI_Cmd()函數(shù)啟用或禁用 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?()函數(shù)可用于將數(shù)據(jù)寫入目標寄存器。首先,我們需要檢查 SPI 狀態(tài)寄存器是否空閑。我們可以在while循環(huán)下使用SPI_GetFlagStatus(SPI_FLAG_BSY)函數(shù)來檢查SPI通信的狀態(tài)。“?GPIO_WriteLow(ChipSelect_port, ChipSelect_pin)”函數(shù)用于向使用頭文件開頭的“?ChipSelect_port”和“ChipSelect_pin”定義的片選引腳發(fā)送“0”信號。然后“SPI_SendData(slave_address)”用于發(fā)送“slave_address”所在的從地址參數(shù)包含從設備的目標寄存器的地址。然后我們需要等到發(fā)送緩沖區(qū)清空。然后我們將使用“SPI_SendData(value)”發(fā)送值。然后我們需要再次檢查發(fā)送緩沖區(qū)的狀態(tài),我們需要等到它為空。現(xiàn)在,我們可以使用“GPIO_WriteHigh(ChipSelect_port, ChipSelect_pin)”將芯片選擇引腳設置為高電平。
在 STM8S 上執(zhí)行 SPI 時可能會遇到一些錯誤。我已經提到了我在執(zhí)行此操作時遇到的錯誤。IE
“while(!SPI_GetFlagStatus(SPI_FLAG_TXE))”循環(huán)永遠不會中斷。這意味著發(fā)送緩沖區(qū)不為空。您可以使用“ SPI_SendData()?”函數(shù)檢查您發(fā)送的地址位?;蛘吣梢詸z查您的接線設置,如果所有電線都正確連接。
在stm8s_max72xx.h頭文件里面:
“?stm8s_max7xx.h”頭文件有一些功能,可在使用 SPI 通信將 8x8 MAX72xx Led 矩陣顯示板與 STM8S 連接時使用。在這個文件的開頭,我已經為設備寄存器單獨定義了一些宏。這些地址可以從MAX72xx IC的數(shù)據(jù)表中找到。
?
#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 數(shù)組?!?alpha_char[26][8]”是一個二維 (2D) 數(shù)組,其中包含 8x8 Led 矩陣的每個字母表的八個 8 位地址。例如,讓我們查看“?alpha_char”的第 0個索引,我們有 8 個 8 位十六進制數(shù)據(jù)。此十六進制數(shù)據(jù)表示 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()”函數(shù)來獲取字符串的長度。我創(chuàng)建了一個MAX7219_init()函數(shù)來將 MAX7219 LED 矩陣初始化為從設備。在這個函數(shù)中,你可以看到我已經在“?GPIO_MODE_OUT_PP_HIGH_FAST ”模式下初始化了“ChipSelect_port”和“ChipSelect_pin”。我們需要按照數(shù)據(jù)表使用該寄存器命令來初始化 MAX7219。我調用了“SPI_write()”函數(shù)將數(shù)據(jù)寫入我在頭文件頂部定義的電阻器中。
?
無效 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)”函數(shù)用于清除 LED 矩陣。我在“zeros_clr[8]”數(shù)組中使用了 8 個 8 位 0 。然后我在 for 循環(huán)中使用該數(shù)組的每一位將 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[][]”數(shù)組的字母索引。在函數(shù)內部,我們有“SPI_write()”。這次我們提供了 Led 矩陣的行和列的寄存器值,以將數(shù)據(jù)寫入特定的 LED。
?
void display_char (int alphabet_sequence) { 無符號整數(shù) 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 文件中:
現(xiàn)在,我們有了要討論的main.c文件。在main.c文件中,我們有三個函數(shù)。即main()、clock_setup()和GPIO_setup()。在clock_setup()函數(shù)中,我使用了CLK_DeInit()函數(shù)來停止微控制器內部任何先前啟動的時鐘。您可以輕松獲得此處使用的每個函數(shù)和參數(shù)的詳細說明。您需要使用我之前討論過的“轉到定義”方法。在GPIO_setup() 中,我使用GPIO_DeInit()函數(shù)去初始化端口 C。然后我初始化了端口 C 的 Pin 5 和 Pin 6?。?通過使用GPIO_Init()函數(shù)。
?
無效時鐘設置(無效) { 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?() 函數(shù)中,我已經調用了我們目前討論的四個函數(shù)。這些函數(shù)可以以相同的順序用于在 STM8S 上建立 SPI 通信。然后我們有“display_clear()”函數(shù)在啟動時清除顯示。然后我用參數(shù)“0”調用“?display_char()?”來顯示字母“A”。在“while()”循環(huán)中,我使用“display_string()”和“display_clear()”函數(shù)來顯示字符串。就我而言,我使用“?CIRCUITDIGEST?”作為字符串顯示在 Led 矩陣顯示器上。它將每隔 2 秒顯示一次該字符串。
至此,我們終于在STM8S103F3P6開發(fā)板上完成了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);
}
評論
查看更多