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文件

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM