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









/////////////////////////////////////////////////////
C文件
#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
////////////////////////////////////////////////////////
H文件

 五、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--;
    
}
////////////////////////////////////////////////////////////
IIC的C文件
#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
////////////////////////////////////////////////////////
IIC的H文件

  六、定时器使用

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);
        }
    }
    
}













































/////////////////////////////////////////////////////
定时器C文件
#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
////////////////////////////////////////////////////////
定时器H文件
原文地址:https://www.cnblogs.com/luckytimor/p/14840941.html