-
工程準備,例程在此鏈接的基礎上添加的
https://blog.csdn.net/mygod2008ok/article/details/107142245
-
加入stm32f0xx_hal_spi.c和stm32f0xx_hal_spi_ex.c到工程
-
在stm32f0xx_hal_config.h文件打開HAL_SPI_MODULE_ENABLED宏
-
新建BSP_spi.c,BSP_spi.h,BSP_lcd_device.c和BSP_lcd_device.h並加入的工程
-
BSP_spi.c的內容如下
#include "BSP_spi.h"
#include "stm32f0xx_hal_spi.h"
#include "stm_log.h"
SPI_HandleTypeDef SpiHandle;
static DMA_HandleTypeDef hdma_tx;
static DMA_HandleTypeDef hdma_rx;
/**
* @brief spi initialization
*/
void BSP_spi_init()
{
/*##-1- Configure the SPI peripheral #######################################*/
/* Set the SPI parameters */
SpiHandle.Instance = SPIx;
SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;
SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
SpiHandle.Init.CRCPolynomial = 7;
SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
SpiHandle.Init.NSS = SPI_NSS_SOFT;
SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
SpiHandle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
SpiHandle.Init.CRCLength = SPI_CRC_LENGTH_8BIT;
SpiHandle.Init.Mode = SPI_MODE_MASTER;
HAL_StatusTypeDef err_code = HAL_SPI_Init(&SpiHandle);
APP_ERROR_CHECK(err_code);
/*初始化CS引腳*/
SPIx_MOSI_GPIO_CS_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct;
/* -2- Configure IOs in output push-pull mode to drive external LEDs */
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Pin = SPIx_CS_PIN;
HAL_GPIO_Init(SPIx_CS_GPIO_PORT, &GPIO_InitStruct);
}
/**
* @brief spi de-initialization
*/
void BSP_spi_deinit()
{
HAL_SPI_DeInit(&SpiHandle);
HAL_GPIO_DeInit(SPIx_CS_GPIO_PORT, SPIx_CS_PIN);
SPIx_MOSI_GPIO_CS_DISABLE();
}
/**
* @brief 傳輸數據
* @param None
* @retval None
*/
void BSP_spi_transmit_data(uint8_t *tx_buf,uint8_t *rx_buf,uint16_t size)
{
uint32_t retry=0,out_time=5000;
SPIx_CS_ENABLE;
while (HAL_SPI_GetState(&SpiHandle) != HAL_SPI_STATE_READY)
{
retry++;
if(retry>200)
{
NRF_LOG_INFO("SPI state no ready before transmit");
SPIx_CS_DISABLE;
return;
}
}
HAL_SPI_TransmitReceive(&SpiHandle, tx_buf, rx_buf, size, out_time);
while (HAL_SPI_GetState(&SpiHandle) != HAL_SPI_STATE_READY)
{
retry++;
if(retry>200)
{
NRF_LOG_INFO("SPI state no ready after transmit");
SPIx_CS_DISABLE;
return;
}
}
SPIx_CS_DISABLE;
}
/**
* @brief SPI MSP Initialization
* This function configures the hardware resources used in this example:
* - Peripheral's clock enable
* - Peripheral's GPIO Configuration
* - DMA configuration for transmission request by peripheral
* - NVIC configuration for DMA interrupt request enable
* @param hspi: SPI handle pointer
* @retval None
*/
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{
GPIO_InitTypeDef GPIO_InitStruct;
if (hspi->Instance == SPIx)
{
/*##-1- Enable peripherals and GPIO Clocks #################################*/
/* Enable GPIO TX/RX clock */
SPIx_SCK_GPIO_CLK_ENABLE();
SPIx_MISO_GPIO_CLK_ENABLE();
SPIx_MOSI_GPIO_CLK_ENABLE();
/* Enable SPI3 clock */
SPIx_CLK_ENABLE();
/* Enable DMA1 clock */
DMAx_CLK_ENABLE();
/*##-2- Configure peripheral GPIO ##########################################*/
/* SPI SCK GPIO pin configuration */
GPIO_InitStruct.Pin = SPIx_SCK_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = SPIx_SCK_AF;
HAL_GPIO_Init(SPIx_SCK_GPIO_PORT, &GPIO_InitStruct);
/* SPI MISO GPIO pin configuration */
GPIO_InitStruct.Pin = SPIx_MISO_PIN;
GPIO_InitStruct.Alternate = SPIx_MISO_AF;
HAL_GPIO_Init(SPIx_MISO_GPIO_PORT, &GPIO_InitStruct);
/* SPI MOSI GPIO pin configuration */
GPIO_InitStruct.Pin = SPIx_MOSI_PIN;
GPIO_InitStruct.Alternate = SPIx_MOSI_AF;
HAL_GPIO_Init(SPIx_MOSI_GPIO_PORT, &GPIO_InitStruct);
/*##-3- Configure the DMA ##################################################*/
/* Configure the DMA handler for Transmission process */
hdma_tx.Instance = SPIx_TX_DMA_STREAM;
hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_tx.Init.Mode = DMA_NORMAL;
hdma_tx.Init.Priority = DMA_PRIORITY_LOW;
HAL_DMA_Init(&hdma_tx);
/* Associate the initialized DMA handle to the the SPI handle */
__HAL_LINKDMA(hspi, hdmatx, hdma_tx);
/* Configure the DMA handler for Transmission process */
hdma_rx.Instance = SPIx_RX_DMA_STREAM;
hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_rx.Init.Mode = DMA_NORMAL;
hdma_rx.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_Init(&hdma_rx);
/* Associate the initialized DMA handle to the the SPI handle */
__HAL_LINKDMA(hspi, hdmarx, hdma_rx);
/*##-4- Configure the NVIC for DMA #########################################*/
/* NVIC configuration for DMA transfer complete interrupt (SPI3_TX) */
HAL_NVIC_SetPriority(SPIx_DMA_TX_IRQn, 1, 1);
HAL_NVIC_EnableIRQ(SPIx_DMA_TX_IRQn);
/* NVIC configuration for DMA transfer complete interrupt (SPI3_RX) */
HAL_NVIC_SetPriority(SPIx_DMA_RX_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(SPIx_DMA_RX_IRQn);
}
}
/**
* @brief SPI MSP De-Initialization
* This function frees the hardware resources used in this example:
* - Disable the Peripheral's clock
* - Revert GPIO, DMA and NVIC configuration to their default state
* @param hspi: SPI handle pointer
* @retval None
*/
void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi)
{
if (hspi->Instance == SPIx)
{
/*##-1- Reset peripherals ##################################################*/
SPIx_FORCE_RESET();
SPIx_RELEASE_RESET();
/*##-2- Disable peripherals and GPIO Clocks ################################*/
/* Configure SPI SCK as alternate function */
HAL_GPIO_DeInit(SPIx_SCK_GPIO_PORT, SPIx_SCK_PIN);
/* Configure SPI MISO as alternate function */
HAL_GPIO_DeInit(SPIx_MISO_GPIO_PORT, SPIx_MISO_PIN);
/* Configure SPI MOSI as alternate function */
HAL_GPIO_DeInit(SPIx_MOSI_GPIO_PORT, SPIx_MOSI_PIN);
/*##-3- Disable the DMA ####################################################*/
/* De-Initialize the DMA associated to transmission process */
HAL_DMA_DeInit(&hdma_tx);
/* De-Initialize the DMA associated to reception process */
HAL_DMA_DeInit(&hdma_rx);
/*##-4- Disable the NVIC for DMA ###########################################*/
HAL_NVIC_DisableIRQ(SPIx_DMA_TX_IRQn);
HAL_NVIC_DisableIRQ(SPIx_DMA_RX_IRQn);
}
}
-
BSP_spi.h的內容如下:
#ifndef __BSP_SPI_H_
#define __BSP_SPI_H_
#include "main.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Definition for SPIx clock resources 使能相關時鐘*/
#define SPIx SPI1
#define SPIx_CLK_ENABLE() __HAL_RCC_SPI1_CLK_ENABLE()
#define DMAx_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE()
#define SPIx_SCK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define SPIx_MISO_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define SPIx_MOSI_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define SPIx_MOSI_GPIO_CS_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define SPIx_MOSI_GPIO_CS_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE()
#define SPIx_FORCE_RESET() __HAL_RCC_SPI1_FORCE_RESET()
#define SPIx_RELEASE_RESET() __HAL_RCC_SPI1_RELEASE_RESET()
/* Definition for SPIx Pins 引腳映射關係*/
#define SPIx_SCK_PIN GPIO_PIN_5
#define SPIx_SCK_GPIO_PORT GPIOA
#define SPIx_SCK_AF GPIO_AF0_SPI1
#define SPIx_MISO_PIN GPIO_PIN_6
#define SPIx_MISO_GPIO_PORT GPIOA
#define SPIx_MISO_AF GPIO_AF0_SPI1
#define SPIx_MOSI_PIN GPIO_PIN_7
#define SPIx_MOSI_GPIO_PORT GPIOA
#define SPIx_MOSI_AF GPIO_AF0_SPI1
#define SPIx_CS_PIN GPIO_PIN_4
#define SPIx_CS_GPIO_PORT GPIOA
/* Definition for SPIx's DMA */
#define SPIx_TX_DMA_STREAM DMA1_Channel3
#define SPIx_RX_DMA_STREAM DMA1_Channel2
/* Definition for SPIx's NVIC */
#define SPIx_DMA_TX_IRQn DMA1_Channel2_3_IRQn
#define SPIx_DMA_RX_IRQn DMA1_Channel2_3_IRQn
#define SPIx_DMA_TX_IRQHandler DMA1_Channel2_3_IRQHandler
#define SPIx_DMA_RX_IRQHandler DMA1_Channel2_3_IRQHandler
/* Size of buffer */
//#define BUFFERSIZE (COUNTOF(aTxBuffer) - 1)
#define SPIx_CS_ENABLE HAL_GPIO_WritePin(SPIx_CS_GPIO_PORT,SPIx_CS_PIN,GPIO_PIN_RESET)
#define SPIx_CS_DISABLE HAL_GPIO_WritePin(SPIx_CS_GPIO_PORT,SPIx_CS_PIN,GPIO_PIN_SET)
/* Exported macro ------------------------------------------------------------*/
#define COUNTOF(__BUFFER__) (sizeof(__BUFFER__) / sizeof(*(__BUFFER__)))
/* Exported functions ------------------------------------------------------- */
extern SPI_HandleTypeDef SpiHandle;
void BSP_spi_init(void);
void BSP_spi_deinit(void);
void BSP_spi_transmit_data(uint8_t *tx_buf,uint8_t *rx_buf,uint16_t size);
#ifdef __cplusplus
}
#endif
#endif
-
BSP_lcd_device.c內容如下:
#include "BSP_lcd_device.h"
#include "BSP_delay.h"
#include "main.h"
#include "stm_log.h"
//-----------8X16數字--------------
const uint8_t digit_8x16_icon[][16] = {
{
0xFF,0xFE,0xFF,0xFE,0xC0,0x06,0xC0,0x06,
0xC0,0x06,0xC0,0x06,0xFF,0xFE,0xFF,0xFE
}, // 0
{
0x00,0x00,0x20,0x06,0x60,0x06,0xFF,0xFE,
0xFF,0xFE,0x00,0x06,0x00,0x06,0x00,0x00
}, // 1
{
0xC3,0xFE,0xC3,0xFE,0xC3,0x06,0xC3,0x06,
0xC3,0x06,0xC3,0x06,0xFF,0x06,0xFF,0x06
}, // 2
{
0x00,0x00,0xC0,0x06,0xC3,0x06,0xC3,0x06,
0xC3,0x06,0xC3,0x06,0xFF,0xFE,0xFF,0xFE
}, // 3
{
0x0F,0xE0,0x3F,0xE0,0xF0,0x60,0xC0,0x60,
0x3F,0xFE,0x3F,0xFE,0x00,0x60,0x00,0x60
}, // 4
{
0xFF,0x06,0xFF,0x06,0xC3,0x06,0xC3,0x06,
0xC3,0x06,0xC3,0x06,0xC3,0xFE,0xC3,0xFE
}, // 5
{
0xFF,0xFE,0xFF,0xFE,0xC3,0x06,0xC3,0x06,
0xC3,0x06,0xC3,0x06,0xC3,0xFE,0xC3,0xFE
}, // 6
{
0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,
0xC0,0xFE,0xCF,0xFE,0xFF,0x00,0xF0,0x00
}, // 7
{
0xFF,0xFE,0xFF,0xFE,0xC3,0x06,0xC3,0x06,
0xC3,0x06,0xC3,0x06,0xFF,0xFE,0xFF,0xFE
}, // 8
{
0xFF,0x06,0xFF,0x06,0xC3,0x06,0xC3,0x06,
0xC3,0x06,0xC3,0x06,0xFF,0xFE,0xFF,0xFE
} // 9
};
//-------------------percent--------------------------
const uint8_t percent_icon[] = {
0x00,0x00,0x00,0x00,0x3E,0x00,0x00,0x7F,
0x00,0x00,0x63,0x02,0x00,0x63,0x0E,0x00,
0x7F,0x1C,0x00,0x3E,0x70,0x00,0x00,0xE0,
0x00,0x03,0x80,0x00,0x07,0x3E,0x00,0x1C,
0x7F,0x00,0x38,0x63,0x00,0x20,0x63,0x00,
0x00,0x7F,0x00,0x00,0x3E,0x00,0x00,0x00
};
#define DISPLAY_MODE 0 // 0 白字黑底 1 黑字白底
//0-63(y的偏移量)一次1位
#define LCD_Y_ADDR 0x40//start line(低6位有效)
//0-15(0-7有效區間,y的偏移量)一次8位
#define LCD_PAGE_ADDR 0xb0//設置頁的地址(低四位)
//0-255(0-127有效區間,x的偏移量)一次一位
#define LCD_X_ADDR_H 0x10//設置列COLUMN的高地址(低四位)
#define LCD_X_ADDR_L 0x00//設置列COLUMN的低地址(低四位)
static uint8_t highToLowByte(uint8_t data)
{
uint8_t temp=0;
for(uint8_t i=0;i<8;i++)
{
temp<<=1;
temp|=(data&0x01);
data>>=1;
}
return temp;
}
static void lcdWriteCmd(uint8_t cmd)
{
uint8_t rx_buf[1];
LCD_PIN_CMD;
BSP_spi_transmit_data(&cmd,rx_buf,1);
}
static void lcdWriteData(uint8_t data)
{
uint8_t rx_buf[1];
LCD_PIN_DATA;
BSP_spi_transmit_data(&data,rx_buf,1);
}
/** @brief 設置x,y的page起始地址
* @param x:0-127
* @param page:0-7
* @retval
*/
static void lcdAddrSet(uint8_t x,uint8_t page)
{
uint8_t x_addrl,x_addrh;
if((x>127)||(page>7))
NRF_LOG_INFO("LCD_ADDR_OVER:X=%d,PAGE=%d",x,page);
x_addrh=(x>>4)&0x0f;
x_addrh|=LCD_X_ADDR_H;
x_addrl=x&0x0f;
x_addrl|=LCD_X_ADDR_L;
// y++;//計算要從1開始
// page=y/8;
// remain=y%8;
// (remain>0)?(page++):(page);
// if(page)//從0開始的
// page--;
// really_page=page;
//// NRF_LOG_INFO("PAGE=%d",page);
// page|=LCD_PAGE_ADDR;
page&=0x0f;
page|=LCD_PAGE_ADDR;
lcdWriteCmd(x_addrh);
lcdWriteCmd(x_addrl);
lcdWriteCmd(page);
}
void app_lcd_fill_ram(uint8_t data)
{
for(uint8_t i=0;i<8;i++)
{
lcdAddrSet(0,i);
for(uint8_t j=0;j<128;j++)
{
lcdWriteData(data);
}
}
}
//void lcdAnyRamClear(uint8_t start_x,uint8_t stop_x,uint8_t start_page,uint8_t stop_page)
//{
// for(uint8_t i=start_page;i<=stop_page;i++)
// {
// lcdAddrSet(start_x,i);
// for(uint8_t j=start_x;j<=stop_x;j++)
// {
// lcdWriteData(0x00);
// }
// }
//}
/** @brief 顯示圖片,長度隨意,高度要是8的倍數,否則就直接丟失(若顯示也會影響其它內容,擦除就是一頁的)
* @param 圖片是從上到下,從左到右。MSB格式(lcd用的是LSB格式,函數裏面有轉換)
* @param
* @retval
*/
static void lcdShowPic(uint8_t x,uint8_t page,uint8_t width, uint8_t high,const uint8_t *bmp)
{
int x2,page2,i,j,k;
x2=x+width;//不包含此地址
page2=page+high/8;//不包含此地址,餘數直接丟掉
// uint16_t c=0;
for(i=x;i<x2;i++) //循環PAGE數/高
{
for(j=page;j<page2;j++) //循環字節數/行/寬
{
lcdAddrSet(i,j);
k=*bmp++; //取圖形數據
k=highToLowByte(k);
//NRF_LOG_INFO("X=%d,PAGE=%d,data=%x,c=%d",i,j,k,c++);
//HAL_Delay(10);
lcdWriteData(k);
}
}//lcd_data(0xff);
}
/**
* @brief 繪製百分比,升級STM32使用
*/
void draw_percent(void)
{
app_lcd_fill_ram(0);
lcdShowPic(64,3,8,16,&digit_8x16_icon[0][0]);
lcdShowPic(74,2,16,24,percent_icon);
}
void BSP_lcd_driver_init(void)
{
//init gpio
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
GPIO_InitStruct.Pin = LCD_CD_PIN|LCD_RESET_PIN;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
//init spi
BSP_spi_init();
//init lcd
LCD_RESET_PIN_EN;
delay_ms(200);
LCD_RESET_PIN_DIS;
delay_ms(500);
lcdWriteCmd(0xE2); //Software Reset
delay_ms(10);
lcdWriteCmd(0xA2); //Set Bias 0xA3 1/7bias, 0xA2 1/9 bias
lcdWriteCmd(0xA0); //左到右Segment Direction Select bit0=0,normal ,=1,reverse
lcdWriteCmd(0xC8); //從上到下Common Direction Select bit3=0,normal ,=1,revese
lcdWriteCmd(0xA6|DISPLAY_MODE); //反顯否 最後一位控制
lcdWriteCmd(0xA4); //正常顯示/全顯
lcdWriteCmd(0x24); //調電壓 對比度 Set internal rb/ra 0x24
lcdWriteCmd(0x81); //Set Contrast
lcdWriteCmd(0x22); //調電壓 對比度
lcdWriteCmd(0x2F); //Power Control Set
lcdWriteCmd(0x2F); //Power Control Set
lcdWriteCmd(0x2F);
delay_ms(40); //delay 40mS
lcdWriteCmd(0x40); //Set Display Start Line
lcdWriteCmd(0xAF); //Display ON
//write data
app_lcd_fill_ram(0x00);
draw_percent();
}
void BSP_lcd_driver_deinit(void)
{
app_lcd_fill_ram(0x00);
lcdWriteCmd(0xAE); //Display Off
lcdWriteCmd(0x28); //Power Control Set
lcdWriteCmd(0x28); //Power Control Set
lcdWriteCmd(0x28);
BSP_spi_deinit();
}
-
BSP_lcd_device.h的內容如下:
#ifndef __BSP_LCD_DEVICE_H_
#define __BSP_LCD_DEVICE_H_
#include "BSP_spi.h"
#include "main.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LCD_CD_PIN GPIO_PIN_3
#define LCD_RESET_PIN GPIO_PIN_8
#define LCD_PIN_DATA HAL_GPIO_WritePin(GPIOA,LCD_CD_PIN,GPIO_PIN_SET)
#define LCD_PIN_CMD HAL_GPIO_WritePin(GPIOA,LCD_CD_PIN,GPIO_PIN_RESET)
#define LCD_RESET_PIN_DIS HAL_GPIO_WritePin(GPIOA,LCD_RESET_PIN,GPIO_PIN_SET)
#define LCD_RESET_PIN_EN HAL_GPIO_WritePin(GPIOA,LCD_RESET_PIN,GPIO_PIN_RESET)
#define ONE_PAGE_LEN 8
typedef enum
{
LCD_CMD=0,
LCD_DATA=1,
}LCD_CD_T;
void BSP_lcd_driver_init(void);
void BSP_lcd_driver_deinit(void);
void app_lcd_fill_ram(uint8_t data);
void draw_percent(void);
#ifdef __cplusplus
}
#endif
#endif
在stm32f0xx_it.c的SPIx_DMA_RX_IRQHandler函數中調用DMA處理函數
/**
* @brief This function handles DMA interrupt request.
* @param None
* @retval None
*/
void SPIx_DMA_RX_IRQHandler(void)
{
HAL_DMA_IRQHandler(SpiHandle.hdmarx);
HAL_DMA_IRQHandler(SpiHandle.hdmatx);
}
最後在main數中調用BSP_lcd_driver_init函數初時化12864
-
DEMO下載地址:
https://download.csdn.net/download/mygod2008ok/12556346