前言
以前玩過一點 STM32 單片機(主要是 STM32F103 系列),去年(2017)STM32F1 漲到不知哪里去了,今年好像降下來了。F0 系列相比 F1 系列少了一些功能,最高主頻只到 48M(F1 是 72M),但是價格便宜啊,剛好最近工作需要重新接觸了 STM32F030,記錄一下。PS:研究了幾天覺得 STM32 的各個組成部分還是很精妙的,雖然繁雜但是庫函數化解了這個問題。
步驟
SPI 初始化
STM32F030 默認的 SPI1 接口如下,其中 CSN 由軟件控制,所以可以改為其他 IO 口
#define SPI1_PORT GPIOA
#define PIN_SPI1_CSN GPIO_Pin_4
#define PIN_SPI1_SCK GPIO_Pin_5
#define PIN_SPI1_MISO GPIO_Pin_6
#define PIN_SPI1_MOSI GPIO_Pin_7
#define SPI1_CSN_L (SPI1_PORT->BRR = PIN_SPI1_CSN)
#define SPI1_CSN_H (SPI1_PORT->BSRR = PIN_SPI1_CSN)
初始化
void SPI1_INIT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //復用功能
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽輸出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; //中速
GPIO_InitStructure.GPIO_Pin = PIN_SPI1_SCK | PIN_SPI1_MOSI | PIN_SPI1_MISO;
GPIO_Init(SPI1_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(SPI1_PORT, GPIO_PinSource5, GPIO_AF_0);
GPIO_PinAFConfig(SPI1_PORT, GPIO_PinSource6, GPIO_AF_0);
GPIO_PinAFConfig(SPI1_PORT, GPIO_PinSource7, GPIO_AF_0);
GPIO_InitStructure.GPIO_Pin = PIN_SPI1_CSN; //配置 CSN
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //高速
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //輸出模式
GPIO_Init(SPI1_PORT, &GPIO_InitStructure);
SPI_I2S_DeInit(SPI1); //將寄存器重設為缺省值
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //雙線雙向全雙工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主機模式
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //8 位幀結構
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //通信空閑時 SCK 為低電平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //第一個時鍾沿捕獲
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //軟件控制 NSS
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //SPI 速度 8 分頻
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //數據傳輸從 MSB 開始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC 校驗
SPI_Init(SPI1, &SPI_InitStructure);
SPI_RxFIFOThresholdConfig(SPI1, SPI_RxFIFOThreshold_QF); //重要,把應答數據位設置為 8 位
SPI_Cmd(SPI1, ENABLE);
}
傳輸數據
讀取和發送數據需要檢查標志位
void SPI1_WriteByte(uint8_t TxData)
{
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); //檢查發送是否完成
SPI_SendData8(SPI1, TxData);
}
uint8_t SPI1_ReadByte(void)
{
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); //檢查接收標志位
return(SPI_ReceiveData8(SPI1));
}
uint8_t SPI1_Transfer(uint8_t data)
{
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_SendData8(SPI1, data);
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
return SPI_ReceiveData8(SPI1);
}
例子
用 SPI 與 NRF24L01 模塊通信
void NRF24L01_Write_Register(uint8_t reg, uint8_t data)
{
SPI1_CSN_L;
SPI1_Transfer(reg);
SPI1_Transfer(data);
SPI1_CSN_H;
}
uint8_t NRF24L01_Read_Register(uint8_t reg)
{
uint8_t tmp;
SPI1_CSN_L;
SPI1_Transfer(reg);
tmp = SPI1_Transfer(0);
SPI1_CSN_H;
return tmp;
}
