LL库使用
一、前言
LL相比较HAL占用空间小很多,执行效率更高,以后也更加的支持LL库;
二、基础工程建立
使用的库选择
三、GPIO使用
主要实现:拉高,拉低,取反,读取
#ifdef defLED1 #define LED1_ON (LL_GPIO_SetOutputPin(LED1_GPIO_Port,LED1_Pin)) #define LED1_OFF (LL_GPIO_ResetOutputPin(LED1_GPIO_Port,LED1_Pin)) #define LED1_RE (LL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin)) #define LED1_IN_STA (LL_GPIO_ISInputPinSet(LED1_GPIO_Port,LED1_Pin) == GPIO_PIN_SET) //读取电平状态,可以判断LED1是点亮还是熄灭 #endif
四、串口使用
1、普通中断方式
主要实现收到数据马上发出去
//初始化
void bsp_uartxInit(void) { LL_USART_EnableIT_RXNE(USART1); LL_USART_EnableIT_PE(USART1); } //中断调用 void LL_UARTX_PeriodElapsedCallback(USART_TypeDef *luart) { uint8_t tmp; if(luart == USART1) { if(LL_USART_IsActiveFlag_RXNE(USART1)) //检测是否接收中断 { tmp=LL_USART_ReceiveData8(USART1); //读取出来接收到的数据 LL_USART_TransmitData8(USART1,tmp); //把数据再从串口发送出去 } } }
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
LL_UARTX_PeriodElapsedCallback(USART1);
/* USER CODE END USART1_IRQn 0 */
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
2、空闲中断方式
3、DMA空闲中断方式
注意bsp_uartxInit();放到初始化位置,LL_DMA_UART_PeriodElapsedCallback放到用到的DMA中断里面。
// Header: // File Name: // Author:LQW // Date:2021/ #include "bsp_uartx.h" #ifdef defUART1 stuUx stuU1; #endif uint8_t gdma_ch = 0; stuUx *gpUx; DMA_TypeDef *gDMAx; USART_TypeDef *gluartx; void bsp_uartxInit(void) { #ifdef defUART1 gpUx = &stuU1; gDMAx = DMA1; gdma_ch = LL_DMA_CHANNEL_4; gluartx = USART1; LL_DMA_SetPeriphAddress(gDMAx, gdma_ch, (uint32_t)(&gluartx->TDR));//外设地址 LL_DMA_SetMemoryAddress(gDMAx, gdma_ch, (uint32_t)gpUx->TxDataBuff);//数据地址 LL_DMA_SetDataLength(gDMAx, gdma_ch, TX_MAX_SIZE);// //添加 LL_USART_ClearFlag_TC(gluartx); LL_USART_EnableIT_TC(gluartx); LL_DMA_EnableIT_TC(gDMAx, gdma_ch); LL_USART_EnableDMAReq_TX(gluartx); gpUx = &stuU1; gDMAx = DMA1; gdma_ch = LL_DMA_CHANNEL_5; gluartx = USART1; LL_DMA_SetPeriphAddress(gDMAx, gdma_ch, (uint32_t)(&gluartx->RDR));//外设地址 LL_DMA_SetMemoryAddress(gDMAx, gdma_ch, (uint32_t)gpUx->RxDataIng);//数据地址 LL_DMA_SetDataLength(gDMAx, gdma_ch, RX_MAX_SIZE);// LL_DMA_EnableIT_TC(gDMAx, gdma_ch); LL_DMA_EnableChannel(gDMAx, gdma_ch); LL_USART_EnableDMAReq_RX(gluartx); LL_USART_ClearFlag_IDLE(gluartx); LL_USART_EnableIT_IDLE(gluartx); #endif } /** *@FUN: *@PRO: *@BAK:LQW */int LL_DMA_UART_PeriodElapsedCallback(void) {// #ifdef defUART1 if(LL_DMA_IsActiveFlag_GI5(DMA1))//DMA1-CH5 全局中断 { if(LL_DMA_IsActiveFlag_TC5(DMA1)) //检测是否发送完成 { LL_DMA_ClearFlag_TC5(DMA1); } if(LL_DMA_IsActiveFlag_TE5(DMA1)) //检测是否发送完成 { LL_DMA_ClearFlag_TE5(DMA1); } LL_DMA_ClearFlag_GI5(DMA1); } if(LL_DMA_IsActiveFlag_GI4(DMA1))//DMA1-CH5 全局中断 { if(LL_DMA_IsActiveFlag_TC4(DMA1)) //检测是否发送完成 { LL_DMA_ClearFlag_TC4(DMA1); } if(LL_DMA_IsActiveFlag_TE4(DMA1)) //检测是否发送完成 { LL_DMA_ClearFlag_TE4(DMA1); } LL_DMA_ClearFlag_GI4(DMA1); } #endif return 0; } //DMA发送 int LL_USART_TX_DMA_EN(USART_TypeDef *luart,uint8_t *buff,uint16_t len) { #ifdef defUART1 gpUx = &stuU1; gDMAx = DMA1; gdma_ch = LL_DMA_CHANNEL_4; gluartx = USART1; #endif LL_DMA_DisableChannel(gDMAx, gdma_ch); memcpy(gpUx->TxDataBuff,buff,len); LL_DMA_SetDataLength(gDMAx, gdma_ch, len); LL_DMA_EnableChannel(gDMAx, gdma_ch); return 0; } /**普通发送 *@FUN: *@PRO: *@BAK:LQW */int LL_USART_TX_EN(USART_TypeDef *luart,uint8_t *buff,uint16_t len) {// uint16_t i=0; for(i=0; i<len; i++) { LL_USART_TransmitData8(luart,buff[i]); //把数据再从串口发送出去 while(READ_BIT(luart->ISR,6) == 0); } return 0; } //// LL_USART_TransmitData8(USART1,tmp); //把数据再从串口发送出去 //接收回调函数 void LL_UARTn_PeriodElapsedCallback(USART_TypeDef *luart) { uint16_t i=0; if(LL_USART_IsActiveFlag_IDLE(luart)) //.检测IDLE标志 { #ifdef defUART1 if(luart == USART1) { gpUx = &stuU1; gDMAx = DMA1; gdma_ch = LL_DMA_CHANNEL_5; } #endif LL_DMA_DisableChannel(gDMAx, gdma_ch); // i = LL_DMA_GetDataLength(gDMAx,gdma_ch); gpUx->RxlenIng = RX_MAX_SIZE-i; LL_DMA_SetDataLength(gDMAx, gdma_ch, RX_MAX_SIZE); LL_DMA_EnableChannel(gDMAx, gdma_ch); LL_USART_ClearFlag_IDLE(luart); LL_USART_ReceiveData8(luart); //读取出来接收到的数据 for(i=0; i < gpUx->RxlenIng; i++) { gpUx->RxDataBuff[i] = gpUx->RxDataIng[i]; gpUx->RxDataIng[i] = 0; } gpUx->Rxlen = gpUx->RxlenIng; gpUx->RxlenIng = 0;// gpUx->TXRX_Sta = urRXok;//标志已经成功接收到一包等待处理 } if(LL_USART_IsActiveFlag_TC(luart)) //.检测TC标志 { #ifdef defUART1 if(luart == USART1) { gpUx = &stuU1; gDMAx = DMA1; gdma_ch = LL_DMA_CHANNEL_4; } #endif LL_USART_ClearFlag_TC(luart); //清除TC中断 可关闭(LL_USART_DisableIT_TC) 防止反复进入TC中断 LL_DMA_DisableChannel(gDMAx, gdma_ch); // 关闭DMA通道(LL_DMA_DisableChannel) } } #ifdef defUART1 /**打印函数 *@FUN: *@PRO: *@BAK: */uint8_t U1_Printf(const char *fmt, ...) { int16_t size =0; va_list va_params; if(_DUGUG_ == 1 ) return 0; //如果处于配置状态,不打印DEBUG数据 va_start(va_params,fmt); size =vsnprintf((char *)stuU1.TxDataBuff,(uint16_t)255,fmt,va_params); va_end(va_params); if(size != -1 ) { #ifdef defU1_EN U1_EN_ON; stuU1.TxTim = 10; #else #endif stuU1.Txlen = size; stuU1.TXRX_Sta = urTXwat; #ifdef defU1_OVERTIM stuU1.RxWaitTim = U1_TxRxOverTim; #endif } return 1; } /** *@FUN: *@PRO: *@BAK: */int U1_Printf_UINT(char *buff,int len) {// if(len >= 0) { #ifdef defU1_EN U1_EN_ON; stuU1.TxTim = 10; #else #endif memcpy(stuU1.TxDataBuff,buff,len); stuU1.Txlen = len; stuU1.TXRX_Sta = urTXwat; #ifdef defU1_OVERTIM stuU1.RxWaitTim = U1_TxRxOverTim; #endif return 0; } return -1; } #endif #ifdef PRINTFX /*-------------------------------------------------*/ /*函数名:串口1 printf函数 */ /*参 数:char* fmt,... 格式化输出字符串和参数 */ /*返回值:无 */ /*-------------------------------------------------*/ __align(8) char Usart1_TxBuff[TX_MAX_SIZE]; void Printf(char* fmt,...) { unsigned int i,length; va_list ap; va_start(ap,fmt); vsprintf(Usart1_TxBuff,fmt,ap); va_end(ap); length=strlen((const char*)Usart1_TxBuff); while((USART1->ISR&0X40)==0); for(i = 0;i < length;i ++) { LL_USART_TransmitData8(USART1,Usart1_TxBuff[i]); } } #endif /////////////////////////////////////////////////////
#ifndef _BSP_UARTX_H #define _BSP_UARTX_H #ifdef __cplusplus extern "C" { #endif #include "main.h" #define U_TEST (1)//串口测试 1发等于收 0实际 #define _DUGUG_ (0)//串口开关 //#define PRINTFX (1) void Printf(char* fmt,...) ; #define Ux_MAX_SIZE (64) #define TX_MAX_SIZE (Ux_MAX_SIZE-1) //发送数据长度,最好等于 #define RX_MAX_SIZE (Ux_MAX_SIZE-1) //定义最大接收字节数 #define Ux_TxRxOverTim (Ux_MAX_SIZE*2) #define defUART1 1 //#define defU1_EN 1 #if defined (defU1_EN) && defined (defUART1) #define U1_EN_ON (LL_GPIO_SetOutputPin(USART1_EN_GPIO_Port,USART1_EN_Pin,GPIO_PIN_SET)) #define U1_EN_OFF (LL_GPIO_SetOutputPin(USART1_EN_GPIO_Port,USART1_EN_Pin,GPIO_PIN_RESET)) #endif typedef enum { urStop, //停止 urIdle, //空闲 urRXing, //接收中 urRXok, //接收完成 urTXwat, //有数据要发送 urTXing, //数据发送中 urTXok, //数据发送完成 urRXwat, //接收等待 urErr, //数据错误 }UART_STA; typedef struct { UART_STA TXRX_Sta; // uint16_t TxTim; //发送状态切换延时时间 // uint16_t RxTim; //帧完成时间 // uint16_t RxIdleTim; //最长空闲时间 // uint16_t RxWaitTim; //等待应答 // uint8_t TxDataIng[TX_MAX_SIZE]; //接收缓冲,最大USART_REC_LEN个字节. uint8_t TxDataBuff[TX_MAX_SIZE]; //接收缓冲,最大USART_REC_LEN个字节. // uint8_t RUData[2]; //发送数据缓冲区 uint8_t RxDataIng[RX_MAX_SIZE]; //发送数据缓冲区 uint8_t RxDataBuff[RX_MAX_SIZE]; //发送数据缓冲区 uint8_t Rxlen; uint8_t RxlenIng; // uint16_t TxlenIng; uint8_t Txlen; union { struct { uint8_t WordLength:1;//数据长度[0] :0- 8位;1-7位 uint8_t Parity:2;//奇偶校验[1:2] :00-无校验; 01-奇校验O; 11-偶校验E uint8_t StopBits:1;//停止位[3]:0-1位;1-2位 uint8_t BaudRate:4;//波特率[4-7]:0-9600; 1-19200;2-38400;3-57600; 4-115200 }stu; uint8_t Da;// 1 229通讯配置: RW }ComSet,ComSetO; }stuUx; #ifdef defUART1 extern stuUx stuU1; #endif void bsp_uartxInit(void); void LL_UARTn_PeriodElapsedCallback(USART_TypeDef *luart); int LL_DMA_UART_PeriodElapsedCallback(void); int LL_USART_TX_DMA_EN(USART_TypeDef *luart,uint8_t *buff,uint16_t len); #ifdef __cplusplus } #endif #endif ////////////////////////////////////////////////////////
五、IIC使用
// Header: // File Name: // Author:LQW // Date:2021/ #include "bsp_iic.h" /**************************************************************************** **函数名称:void I2C1_Read(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *read_Buffer) **功能概要:uint8_t driver_Addr-从器件地址, uint8_t start_Addr-从器件要读取的起始地址, uint8_t number_Bytes-要读取的数据个数, uint8_t *read_Buffer-存放数据首地址 **参数说明:无 **函数返回:无 ****************************************************************************/ void I2C1_Read(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *read_Buffer) { uint8_t read_Num; uint16_t tim_dly = 25000; while(LL_I2C_IsActiveFlag_BUSY(I2C1) != RESET) tim_dly--; LL_I2C_HandleTransfer(I2C1, driver_Addr,LL_I2C_ADDRSLAVE_7BIT,1, LL_I2C_MODE_SOFTEND, LL_I2C_GENERATE_START_WRITE); while(LL_I2C_IsActiveFlag_TXIS(I2C1) == RESET) tim_dly--; LL_I2C_TransmitData8(I2C1, start_Addr); while(LL_I2C_IsActiveFlag_TC(I2C1) == RESET) tim_dly--; LL_I2C_HandleTransfer(I2C1, driver_Addr,LL_I2C_ADDRSLAVE_7BIT,number_Bytes, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_READ); for(read_Num = 0; read_Num < number_Bytes; read_Num++) { while(LL_I2C_IsActiveFlag_RXNE(I2C1) == RESET) tim_dly--; read_Buffer[read_Num] = LL_I2C_ReceiveData8(I2C1); } while(LL_I2C_IsActiveFlag_STOP(I2C1) == RESET) tim_dly--; } /**************************************************************************** **函数名称:void I2C1_Write(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *write_Buffer) **功能概要:I2C写函数 **参数说明:uint8_t driver_Addr-从器件地址, uint8_t start_Addr-从器件要写入的起始地址 uint8_t number_Bytes-要写入的数据个数, uint8_t *write_Buffer-待写入数据的起始地址 **函数返回:无 ****************************************************************************/ void I2C1_Write(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *write_Buffer) { uint8_t write_Num; uint16_t tim_dly = 25000; while(LL_I2C_IsActiveFlag_BUSY(I2C1) != RESET) tim_dly--; LL_I2C_HandleTransfer(I2C1, driver_Addr,LL_I2C_ADDRSLAVE_7BIT, 1, LL_I2C_MODE_RELOAD, LL_I2C_GENERATE_START_WRITE); while(LL_I2C_IsActiveFlag_TXIS(I2C1) == RESET) tim_dly--; LL_I2C_TransmitData8(I2C1, start_Addr); while(LL_I2C_IsActiveFlag_TCR(I2C1) == RESET) tim_dly--; LL_I2C_HandleTransfer(I2C1, driver_Addr,LL_I2C_ADDRSLAVE_7BIT, number_Bytes, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_NOSTARTSTOP); for(write_Num = 0; write_Num < number_Bytes; write_Num++) { while(LL_I2C_IsActiveFlag_TXIS(I2C1) == RESET) tim_dly--; LL_I2C_TransmitData8(I2C1, write_Buffer[write_Num]); } while(LL_I2C_IsActiveFlag_STOP(I2C1) == RESET) tim_dly--; } ////////////////////////////////////////////////////////////
#ifndef _BSP_IIC_H #define _BSP_IIC_H #ifdef __cplusplus extern "C" { #endif #include "main.h" void I2C1_Read(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *read_Buffer); void I2C1_Write(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *write_Buffer); #ifdef __cplusplus } #endif #endif ////////////////////////////////////////////////////////
六、定时器使用
TIMx_Init();//初始化文件
// Header: // File Name: // Author:LQW // Date:2021/ #include "bsp_tim.h" TIM_TypeDef *plltim_1msTim = TIM16; TIM_TypeDef *plltim_xxxTim = TIM17; uint32_t TxCnt[10] = {0}; /** *@FUN: *@PRO: *@BAK: */void Loop1ms(void) {// } /** *@FUN: *@PRO: *@BAK: */void Loop10ms(void) {// } /** *@FUN: *@PRO: *@BAK: */void Loop100ms(void) {// } /** *@FUN: *@PRO: *@BAK: */void Loop1000ms(void) {// LL_IWDG_ReloadCounter(IWDG); } /** *@FUN: *@PRO: *@BAK:LQW */int8_t Loop10s(void) {// return 0; } /**函数执行 *@FUN: *@PRO: *@BAK: */void Time100usLoopProcess(void) {// } /**1ms中断 *@FUN: *@PRO: *@BAK: */void LoopTimx1ms(void) {// Loop1ms(); if(TxCnt[0]++ >= 10-1) {//10ms TxCnt[0] = 0; TxCnt[5]++; Loop10ms(); } if(TxCnt[1]++ >= 100-1) {//100m TxCnt[1] = 0; TxCnt[6]++; Loop100ms(); } if(TxCnt[2]++ >= 1000-1) {//1000ms TxCnt[2] = 0; TxCnt[7]++; Loop1000ms(); } if(TxCnt[3]++ >= 10000-1) {//10s TxCnt[3] = 0; TxCnt[8]++; Loop10s(); } } /** *@FUN: *@PRO: *@BAK:LQW */int TIMx_Init(void) {// LL_TIM_EnableIT_UPDATE(plltim_1msTim);//TIM更新使能 LL_TIM_EnableCounter(plltim_1msTim);//TIM计数使能 LL_TIM_EnableIT_UPDATE(plltim_xxxTim);//TIM更新使能 LL_TIM_EnableCounter(plltim_xxxTim);//TIM计数使能 return 0; } void TIMx_IRQHandler(TIM_TypeDef *llTimx) { if(llTimx == TIM16) { if(LL_TIM_IsActiveFlag_UPDATE(llTimx)) { LoopTimx1ms(); LL_TIM_ClearFlag_UPDATE(llTimx); } } else if(llTimx == TIM17) { if(LL_TIM_IsActiveFlag_UPDATE(llTimx)) { Time100usLoopProcess(); LL_TIM_ClearFlag_UPDATE(llTimx); } } } /////////////////////////////////////////////////////
#ifndef _BSP_TIM_H #define _BSP_TIM_H #ifdef __cplusplus extern "C" { #endif #include "main.h" int TIMx_Init(void); void TIMx_IRQHandler(TIM_TypeDef *llTimx); #ifdef __cplusplus } #endif #endif ////////////////////////////////////////////////////////