【STM32F429開發板用戶手冊】第34章 STM32F429的SPI總線應用之驅動DAC8501(雙路輸出,16bit分辨率,0-5V)


最新教程下載:http://www.armbbs.cn/forum.php?mod=viewthread&tid=93255

第34章       STM32F429的SPI總線應用之驅動DAC8501(雙路輸出,16bit分辨率,0-5V)

本章節為大家講解標准SPI接線方式驅動模數轉換器DAC8501。

34.1 初學者重要提示

34.2 DAC結構分類和技術術語

34.3 DAC8501硬件設計

34.4 DAC8501關鍵知識點整理(重要)

34.5 DAC8501驅動設計

34.6 SPI總線板級支持包(bsp_spi_bus.c)

34.7 DAC8501支持包中斷方式(bsp_spi_dac8501.c)

34.8 DAC8501驅動移植和使用

34.9 實驗例程設計框架

34.10 實驗例程說明(MDK)

34.11 實驗例程說明(IAR)

34.12 總結

 

 

34.1 初學者重要提示

  1.   學習本章節前,務必優先學習第31章。
  2.   DAC8501模塊上帶了兩片8501,每片是單通道DAC,帶片上輸出緩沖運放,軌到軌輸出,16bit分辨率,支持30MHz的SPI時鍾速度。
  3.   我們的H7板子配套了SPI + DMA方式控制DAC8501,而F4系列不方便實現,確切的說是可以用DMA方式,但是不方便控制寫入速度,需要借助定時器中斷進行更新,實用價值不是很大。
  4.   DAC8501數據手冊,模塊原理圖和接線圖都已經放到本章教程配置例子的Doc文件里。
  5.   文件bsp_spi_bus.c文件公共的總線驅動文件,支持串行FLASH、TSC2046、VS1053、AD7705、ADS1256等SPI設備的配置。

34.2 DAC結構分類和技術術語

在本教程的第33章進行了詳細說明。

34.3 DAC8501硬件設計

DAC的原理圖下載:

http://www.armbbs.cn/forum.php?mod=viewthread&tid=97262

34.3.1 DAC8501模塊規格

  • 產品規格:

1、供電電壓: 2.7 - 5.5V【3.3V供電時,輸出電壓也可以到5V】。

2、通道數: 2路  (通過2片DAC8501E實現)。

3、輸出電壓范圍 : 0 - 5V【零位 < 0.020V, 滿位 > 4.970V】。

4、分辨率: 16位。

5、功耗 :  小於10mA。

6、MCU接口 :高速 SPI (30M) 支持 3.3V和5V單片機。

7、DAC輸出模擬帶寬:350KHz。

8、DAC輸出響應: 10uS 到 0.003% FSR。

  • 產品特點:

1、輸出和供電電壓無關;模塊內帶升壓電路和5V基准。

2、自適應單片機的電平(2.7 - 5V 均可以)。

3、輸出電壓軌到軌,最高電壓可以到 4.970V 以上。

  • 產品效果:

 

 

34.3.2 DAC8501硬件接口

V6板子上DAC8501模塊的插座的原理圖如下(NRF24L01,AD9833,DAC8563和TM7705都是用的而這個插座):

 

實際對應開發的位置如下:

 

34.4 DAC8501關鍵知識點整理(重要)

驅動DAC8501需要對下面這些知識點有個認識。

34.4.1 DAC8501基礎信息

  •   單通道DAC,帶片上輸出緩沖運放,軌到軌輸出,16bit分辨率,支持30MHz的SPI時鍾速度。
  •   模擬輸出帶寬350KHz。
  •   供電范圍2.7V到5.5V。
  •   具有低功耗特性。
  •   上電復位輸出0V。

 

34.4.2 DAC8501每個引腳的作用

DAC8501的封裝形式:

 

  •   Vdd

供電范圍2.7-5.5V。

  •   Vref

穩壓基准輸入。

  •   Vfb

輸出運放的反饋。

  •   Vout

模擬輸出電壓,輸出運放具有軌到軌特性。

  •   SYNC (片選)

低電平有效,當SYNC變為低電平時,它使能輸入移位寄存器,並且數據采樣在隨后的時鍾下降沿。 DAC輸出在第24個時鍾下降沿之后更新。 如果SYNC在第23個時鍾沿之前變高,SYNC的上升沿將充當中斷,並且DAC8501將忽略寫序列。

  •   SCLK

時鍾輸入端,支持30MHz。

  •   Din

串行時鍾輸入,每個時鍾下降沿將數據寫到的24bit的輸入移位寄存器。

  •   GND

接地端。

34.4.3 DAC8501輸出電壓計算公式

DAC8501的計算公式如下:

 

  •   D

配置DAC8501數據輸出寄存器的數值,范圍0 到2^16 – 1,即0到65535。

  •   VREF

使用外部參考電壓,由VREFIN引腳的輸入決定。

  •   Vout

輸出電壓。

34.4.4 DAC8501時序圖

DAC8501的時序圖如下:

 

 

這個時序里面有三個參數尤其重要,后面時序配置要用到(對於F4系列主要是第1個參數,H7系列這三個都要用的)。

  •   f(1)

供電2.7到3.6V時,最高時鍾20MHz。

供電3.6到5.5V時,最高時鍾30MHz。

  •  t(4)

SYNC低電平有效到SCLK第1個上降沿信號的時間沒有最小值限制,可以為0。

  •   t(8)

每傳輸24bit數據后,SYNC要保持一段時間的高電平。

供電2.7到3.6V時,最小要求50ns。

供電3.6到5.5V時,最小要求33ns。

34.4.5 DAC8501寄存器配置

DAC8501的寄存器配置是24bit格式:

 

控制DAC8501每次要傳輸24bit數據,高8bit控制位 + 16bit數據位。

控制位的PD1和PD0定義如下:

 

PD1 PD0 決定4種工作模式:

0   0  ---> 正常工作模式

0   1  ---> 輸出接1K歐到GND

1   0  ---> 輸出100K歐到GND

1   1  ---> 輸出高阻

34.5 DAC8501驅動設計(中斷更新方式)

DAC8501的程序驅動框架設計如下:

有了這個框圖,程序設計就比較好理解了。

34.5.1 第1步:SPI總線配置

spi總線配置通過如下兩個函數實現:

/*
*********************************************************************************************************
*    函 數 名: bsp_InitSPIBus
*    功能說明: 配置SPI總線。
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
void bsp_InitSPIBus(void)
{    
    g_spi_busy = 0;
    
    bsp_InitSPIParam(SPI_BAUDRATEPRESCALER_8, SPI_PHASE_1EDGE, SPI_POLARITY_LOW);
}

/*
*********************************************************************************************************
*    函 數 名: bsp_InitSPIParam
*    功能說明: 配置SPI總線參數,時鍾分頻,時鍾相位和時鍾極性。
*    形    參: _BaudRatePrescaler  SPI總線時鍾分頻設置,支持的參數如下:
*                                 SPI_BAUDRATEPRESCALER_2    2分頻
*                                 SPI_BAUDRATEPRESCALER_4    4分頻
*                                 SPI_BAUDRATEPRESCALER_8    8分頻
*                                 SPI_BAUDRATEPRESCALER_16   16分頻
*                                 SPI_BAUDRATEPRESCALER_32   32分頻
*                                 SPI_BAUDRATEPRESCALER_64   64分頻
*                                 SPI_BAUDRATEPRESCALER_128  128分頻
*                                 SPI_BAUDRATEPRESCALER_256  256分頻
*                                                        
*             _CLKPhase           時鍾相位,支持的參數如下:
*                                 SPI_PHASE_1EDGE     SCK引腳的第1個邊沿捕獲傳輸的第1個數據
*                                 SPI_PHASE_2EDGE     SCK引腳的第2個邊沿捕獲傳輸的第1個數據
*                                 
*             _CLKPolarity        時鍾極性,支持的參數如下:
*                                 SPI_POLARITY_LOW    SCK引腳在空閑狀態處於低電平
*                                 SPI_POLARITY_HIGH   SCK引腳在空閑狀態處於高電平
*
*    返 回 值: 無
*********************************************************************************************************
*/
void bsp_InitSPIParam(uint32_t _BaudRatePrescaler, uint32_t _CLKPhase, uint32_t _CLKPolarity)
{
    /* 提高執行效率,只有在SPI硬件參數發生變化時,才執行HAL_Init */
    if (s_BaudRatePrescaler == _BaudRatePrescaler && s_CLKPhase == _CLKPhase && s_CLKPolarity == _CLKPolarity)
    {        
        return;
    }

    s_BaudRatePrescaler = _BaudRatePrescaler;    
    s_CLKPhase = _CLKPhase;
    s_CLKPolarity = _CLKPolarity;
    
    
/* 設置SPI參數 */
    hspi.Instance               = SPIx;                   /* 例化SPI */
    hspi.Init.BaudRatePrescaler = _BaudRatePrescaler;     /* 設置波特率 */
    hspi.Init.Direction         = SPI_DIRECTION_2LINES;   /* 全雙工 */
    hspi.Init.CLKPhase          = _CLKPhase;              /* 配置時鍾相位 */
    hspi.Init.CLKPolarity       = _CLKPolarity;           /* 配置時鍾極性 */
    hspi.Init.DataSize          = SPI_DATASIZE_8BIT;      /* 設置數據寬度 */
    hspi.Init.FirstBit          = SPI_FIRSTBIT_MSB;       /* 數據傳輸先傳高位 */
    hspi.Init.TIMode            = SPI_TIMODE_DISABLE;     /* 禁止TI模式  */
    hspi.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE; /* 禁止CRC */
    hspi.Init.CRCPolynomial     = 7;                       /* 禁止CRC后,此位無效 */
    hspi.Init.NSS               = SPI_NSS_SOFT;            /* 使用軟件方式管理片選引腳 */
    hspi.Init.Mode                  = SPI_MODE_MASTER;    /* SPI工作在主控模式 */

    /* 復位SPI */
    if(HAL_SPI_DeInit(&hspi) != HAL_OK)
    {
        Error_Handler(__FILE__, __LINE__);     
    }


    if (HAL_SPI_Init(&hspi) != HAL_OK)
    {
        Error_Handler(__FILE__, __LINE__);
    }    
}

關於這兩個函數有以下兩點要做個說明:

  •   函數bsp_InitSPIBus里面的配置是個初始設置。實際驅動芯片時,會通過函數bsp_InitSPIParam做再配置。
  •   函數bsp_InitSPIParam提供了時鍾分頻,時鍾相位和時鍾極性配置。驅動不同外設芯片時,基本上調整這三個參數就夠。當SPI接口上接了多個不同類型的芯片時,通過此函數可以方便的切換配置。

34.5.2 第2步:SPI總線的查詢,中斷和DMA方式設置

注:推薦使用查詢方式。

SPI驅動的查詢,中斷和DMA方式主要通過函數bsp_spiTransfer實現數據傳輸:

/*
*********************************************************************************************************
*                                 選擇DMA,中斷或者查詢方式
*********************************************************************************************************
*/
//#define USE_SPI_DMA    /* DMA方式  */
//#define USE_SPI_INT    /* 中斷方式 */
#define USE_SPI_POLL   /* 查詢方式 */

uint8_t g_spiTxBuf[SPI_BUFFER_SIZE];  
uint8_t g_spiRxBuf[SPI_BUFFER_SIZE];

/*
*********************************************************************************************************
*    函 數 名: bsp_spiTransfer
*    功能說明: 啟動數據傳輸
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
void bsp_spiTransfer(void)
{
    if (g_spiLen > SPI_BUFFER_SIZE)
    {
        return;
    }
    
    /* DMA方式傳輸 */
#ifdef USE_SPI_DMA
    wTransferState = TRANSFER_WAIT;
    
    if(HAL_SPI_TransmitReceive_DMA(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)    
    {
        Error_Handler(__FILE__, __LINE__);
    }
    
    while (wTransferState == TRANSFER_WAIT)
    {
        ;
    }
#endif

    /* 中斷方式傳輸 */    
#ifdef USE_SPI_INT
    wTransferState = TRANSFER_WAIT;

    if(HAL_SPI_TransmitReceive_IT(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)    
    {
        Error_Handler(__FILE__, __LINE__);
    }
    
    while (wTransferState == TRANSFER_WAIT)
    {
        ;
    }
#endif

    /* 查詢方式傳輸 */    
#ifdef USE_SPI_POLL
    if(HAL_SPI_TransmitReceive(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen, 1000000) != HAL_OK)    
    {
        Error_Handler(__FILE__, __LINE__);
    }    
#endif
}

通過開頭宏定義可以方便的切換中斷,查詢和DMA方式。

34.5.3 第3步:DAC8501的時鍾極性和時鍾相位配置

首先回憶下STM32F4支持的4種時序配置。

  •   當CPOL = 1, CPHA = 1時

SCK引腳在空閑狀態處於高電平,SCK引腳的第2個邊沿捕獲傳輸的第1個數據。

  •   當CPOL = 0, CPHA = 1時

SCK引腳在空閑狀態處於低電平,SCK引腳的第2個邊沿捕獲傳輸的第1個數據。

  •   當CPOL = 1, CPHA = 0時

SCK引腳在空閑狀態處於高電平,SCK引腳的第1個邊沿捕獲傳輸的第1個數據。

  •   當CPOL = 0 ,CPHA= 0時

SCK引腳在空閑狀態處於低電平,SCK引腳的第1個邊沿捕獲傳輸的第1個數據。

 

有了F4支持的時序配置,再來看下DAC8501的時序圖:

 

首先DAC8501是下降升沿做數據采集,所以STM32F4的可選的配置就是:

CHOL = 0,  CPHA = 1

CHOL = 1,  CPHA = 0

對於這兩種情況的主要區別是空閑狀態下SCLK時鍾選擇高電平還是低電平,根據上面的時序圖和DAC8501的數據手冊,兩種情況下都可以正常運行。經過實際測試,STM32F4使用這兩個配置確實都可以正常運行。程序里面默認是選擇CHOL = 0,  CPHA = 1。

34.5.4 第4步:單SPI接口管理多個SPI設備的切換機制

單SPI接口管理多個SPI設備最麻煩的地方是不同設備的時鍾分配,時鍾極性和時鍾相位並不相同。對此的解決解決辦法是在片選階段配置切換,比如DAC8501的片選:

/*
*********************************************************************************************************
*    函 數 名: DAC8501_SetCS1
*    功能說明: DAC8501 片選控制函數
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
void DAC8501_SetCS1(uint8_t _Level)
{
    if (_Level == 0)
    {
        bsp_SpiBusEnter();    /* 占用SPI總線  */    
        bsp_InitSPIParam(SPI_BAUDRATEPRESCALER_4, SPI_PHASE_2EDGE, SPI_POLARITY_LOW);        
        CS1_0();
    }
    else
    {        
        CS1_1();    
        bsp_SpiBusExit();    /* 釋放SPI總線 */
    }    
}

/*
*********************************************************************************************************
*    函 數 名: DAC8501_SetCS2(0)
*    功能說明: 設置CS2。 用於運行中SPI共享。
*    形    參: 無
    返 回 值: 無
*********************************************************************************************************
*/
void DAC8501_SetCS2(uint8_t _level)
{
    if (_level == 0)
    {
        bsp_SpiBusEnter();    /* 占用SPI總線  */
        bsp_InitSPIParam(SPI_BAUDRATEPRESCALER_4, SPI_PHASE_2EDGE, SPI_POLARITY_LOW);        
        CS2_0();
    }
    else
    {
        CS2_1();
        bsp_SpiBusExit();    /* 釋放SPI總線 */
    }
}

通過這種方式就有效的解決了單SPI接口管理多設備的問題。因為給每個設備都配了一個獨立的片選引腳,這樣就可以為每個設備都配置這么一個片選配置。

但是頻繁配置也比較繁瑣,所以函數bsp_InitSPIParam里面做了特別處理。當前配置與之前配置相同的情況下無需重復配置。

34.5.5 第5步:DAC8501的數據更新

DAC8501的雙通道數據更新通過下面的函數實現:

/*
*********************************************************************************************************
*    函 數 名: DAC8501_SetDacData
*    功能說明: 設置DAC數據
*    形    參: _ch, 通道,
*             _data : 數據
*    返 回 值: 無
*********************************************************************************************************
*/
void DAC8501_SetDacData(uint8_t _ch, uint16_t _dac)
{
    uint32_t data;

    /*
        DAC8501.pdf page 12 有24bit定義

        DB24:18 = xxxxx 保留
        DB17: PD1
        DB16: PD0

        DB15:0  16位數據

        其中 PD1 PD0 決定4種工作模式
              0   0  ---> 正常工作模式
              0   1  ---> 輸出接1K歐到GND
              1   0  ---> 輸出100K歐到GND
              1   1  ---> 輸出高阻
    */

    data = _dac; /* PD1 PD0 = 00 正常模式 */

    if (_ch == 0)
    {
        DAC8501_SetCS1(0);
    }
    else
    {
        DAC8501_SetCS2(0);
    }

    /* DAC8501 SCLK時鍾高達30M,因此可以不延遲 */
    g_spiLen = 0;
    g_spiTxBuf[g_spiLen++] = (data >> 16);
    g_spiTxBuf[g_spiLen++] = (data >> 8);
    g_spiTxBuf[g_spiLen++] = (data);
    bsp_spiTransfer();    

    if (_ch == 0)
    {
        DAC8501_SetCS1(1);
    }
    else
    {
        DAC8501_SetCS2(1);
    }
}

函數實現比較簡單,每次更新發送24bit數據即可。

34.6 SPI總線板級支持包(bsp_spi_bus.c)

SPI總線驅動文件bsp_spi_bus.c主要實現了如下幾個API供用戶調用:

  •   bsp_InitSPIBus
  •   bsp_InitSPIParam
  •   bsp_spiTransfer

34.6.1 函數bsp_InitSPIBus

函數原型:

void bsp_InitSPIBus(void)

函數描述:

此函數主要用於SPI總線的初始化,在bsp.c文件調用一次即可。

34.6.2 函數bsp_InitSPIParam

函數原型:

void bsp_InitSPIParam(uint32_t _BaudRatePrescaler, uint32_t _CLKPhase, uint32_t _CLKPolarity)

函數描述:

此函數用於SPI總線的配置。

函數參數:

  •   第1個參數SPI總線的分頻設置,支持的參數如下:

SPI_BAUDRATEPRESCALER_2    2分頻

SPI_BAUDRATEPRESCALER_4    4分頻

SPI_BAUDRATEPRESCALER_8    8分頻

SPI_BAUDRATEPRESCALER_16   16分頻

SPI_BAUDRATEPRESCALER_32   32分頻

SPI_BAUDRATEPRESCALER_64   64分頻

SPI_BAUDRATEPRESCALER_128  128分頻

SPI_BAUDRATEPRESCALER_256  256分頻

  •   第2個參數用於時鍾相位配置,支持的參數如下:

SPI_PHASE_1EDGE     SCK引腳的第1個邊沿捕獲傳輸的第1個數據

SPI_PHASE_2EDGE     SCK引腳的第2個邊沿捕獲傳輸的第1個數據

  •   第3個參數是時鍾極性配置,支持的參數如下:

SPI_POLARITY_LOW   SCK引腳在空閑狀態處於低電平

SPI_POLARITY_HIGH   SCK引腳在空閑狀態處於高電平

34.6.3 函數bsp_spiTransfer

函數原型:

void bsp_spiTransfer(void)

函數描述:

此函數用於啟動SPI數據傳輸,支持查詢,中斷和DMA方式傳輸。

34.7 DAC8501支持包中斷方式(bsp_spi_dac8501.c)

DAC8501驅動文件bsp_spi_dac8501.c主要實現了如下幾個API供用戶調用:

  •   bsp_InitDAC8501
  •   DAC8501_SetCS1
  •   DAC8501_SetCS2
  •   DAC8501_SetDacData
  •   DAC8501_DacToVoltage
  •   DAC8501_VoltageToDac

34.7.1 函數bsp_InitDAC8501

函數原型:

void bsp_InitDAC8501(void)

函數描述:

主要用於DAC8501的初始化,調用前務必先調用函數bsp_InitSPIBus初始化SPI外設。

34.7.2 函數DAC8501_SetCS1

函數原型:

void DAC8501_SetCS1(uint8_t _Level)

函數描述:

此函數用於片選DAC8501模塊上的第1片8501。

函數參數:

  •   第1個參數為0表示選中,為1表示取消選中。

34.7.3 函數DAC8501_SetCS2

函數原型:

void DAC8501_SetCS2(uint8_t _Level)

函數描述:

此函數用於片選DAC8501模塊上的第2片8501。

函數參數:

  •   第1個參數為0表示選中,為1表示取消選中

34.7.4 函數DAC8501_SetDacData

函數原型:

void DAC8501_SetDacData(uint8_t _ch, uint16_t _dac)

函數描述:

此函數用於設置DAC輸出,並立即更新。

函數參數:

  •   第1個參數為0表示通道1,為1表示通道2。
  •   第2個參數是DAC數值設置,范圍0到65535,0對應最小電壓值,65535對應最大電壓值。

34.7.5 函數DAC8501_DacToVoltage

函數原型:

int32_t DAC8501_DacToVoltage(uint16_t _dac)

函數描述:

此函數用於將DAC值換算為電壓值,單位0.1mV。

函數參數:

  •   第1個參數DAC數值,范圍0到65535。
  •   返回值,返回電壓值,單位0.1mV。

34.7.6 函數DAC8501_VoltageToDac

函數原型:

uint32_t DAC8501_VoltageToDac(int32_t _volt)

函數描述:

此函數用於將電壓值轉換為DAC值。

函數參數:

  •   第1個參數是電壓值,范圍0到50000,單位0.1mV。
  •   返回值,返回DAC值。

34.8 DAC8501驅動移植和使用

DAC8501移植步驟如下:

  •   第1步:復制bsp_spi_bus.c,bsp_spi_bus.h,bsp_spi_dac8501.c,bsp_spi_dac8501.h到自己的工程目錄,並添加到工程里面。
  •   第2步:根據使用的第幾個SPI,SPI時鍾,SPI引腳和DMA通道等,修改bsp_spi_bus.c文件開頭的宏定義
/*
*********************************************************************************************************
*                                時鍾,引腳,DMA,中斷等宏定義
*********************************************************************************************************
*/
#define SPIx                        SPI1

#define SPIx_CLK_ENABLE()            __HAL_RCC_SPI1_CLK_ENABLE()

#define DMAx_CLK_ENABLE()            __HAL_RCC_DMA2_CLK_ENABLE()

#define SPIx_FORCE_RESET()            __HAL_RCC_SPI1_FORCE_RESET()
#define SPIx_RELEASE_RESET()        __HAL_RCC_SPI1_RELEASE_RESET()

#define SPIx_SCK_CLK_ENABLE()        __HAL_RCC_GPIOB_CLK_ENABLE()
#define SPIx_SCK_GPIO                GPIOB
#define SPIx_SCK_PIN                GPIO_PIN_3
#define SPIx_SCK_AF                    GPIO_AF5_SPI1

#define SPIx_MISO_CLK_ENABLE()        __HAL_RCC_GPIOB_CLK_ENABLE()
#define SPIx_MISO_GPIO                GPIOB
#define SPIx_MISO_PIN                 GPIO_PIN_4
#define SPIx_MISO_AF                GPIO_AF5_SPI1

#define SPIx_MOSI_CLK_ENABLE()        __HAL_RCC_GPIOB_CLK_ENABLE()
#define SPIx_MOSI_GPIO                GPIOB
#define SPIx_MOSI_PIN                 GPIO_PIN_5
#define SPIx_MOSI_AF                GPIO_AF5_SPI1

#define SPIx_TX_DMA_CHANNEL         DMA_CHANNEL_3
#define SPIx_TX_DMA_STREAM          DMA2_Stream3
#define SPIx_RX_DMA_CHANNEL         DMA_CHANNEL_3
#define SPIx_RX_DMA_STREAM          DMA2_Stream0


#define SPIx_IRQn                   SPI1_IRQn
#define SPIx_IRQHandler             SPI1_IRQHandler
#define SPIx_DMA_TX_IRQn            DMA2_Stream3_IRQn
#define SPIx_DMA_RX_IRQn            DMA2_Stream0_IRQn
#define SPIx_DMA_TX_IRQHandler      DMA2_Stream3_IRQHandler
#define SPIx_DMA_RX_IRQHandler      DMA2_Stream0_IRQHandler
  •   第3步:根據芯片支持的時鍾速度,時鍾相位和時鍾極性配置函數DAC8501_SetCS1和DAC8501_SetCS2。
/*
*********************************************************************************************************
*    函 數 名: DAC8501_SetCS1
*    功能說明: DAC8501 片選控制函數
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
void DAC8501_SetCS1(uint8_t _Level)
{
    if (_Level == 0)
    {
        bsp_SpiBusEnter();    /* 占用SPI總線  */    
        bsp_InitSPIParam(SPI_BAUDRATEPRESCALER_8, SPI_PHASE_2EDGE, SPI_POLARITY_LOW);        
        CS1_0();
    }
    else
    {        
        CS1_1();    
        bsp_SpiBusExit();    /* 釋放SPI總線 */
    }    
}

/*
*********************************************************************************************************
*    函 數 名: DAC8501_SetCS2(0)
*    功能說明: 設置CS2。 用於運行中SPI共享。
*    形    參: 無
    返 回 值: 無
*********************************************************************************************************
*/
void DAC8501_SetCS2(uint8_t _level)
{
    if (_level == 0)
    {
        bsp_SpiBusEnter();    /* 占用SPI總線  */
        bsp_InitSPIParam(SPI_BAUDRATEPRESCALER_8, SPI_PHASE_2EDGE, SPI_POLARITY_LOW);        
        CS2_0();
    }
    else
    {
        CS2_1();
        bsp_SpiBusExit();    /* 釋放SPI總線 */
    }
}
  •   第4步:根據使用的片選引腳,修改bsp_spi_dac8501.c文件開頭的宏定義。
#define CS1_CLK_ENABLE()     __HAL_RCC_GPIOG_CLK_ENABLE()
#define CS1_GPIO            GPIOG
#define CS1_PIN            GPIO_PIN_10

#define CS1_1()            CS1_GPIO->BSRR = CS1_PIN
#define CS1_0()            CS1_GPIO->BSRR = ((uint32_t)CS1_PIN << 16U)

/* 特別注意,我們這里是用的擴展IO控制的 */    
#define CS2_1()            HC574_SetPin(NRF24L01_CE, 1);
#define CS2_0()            HC574_SetPin(NRF24L01_CE, 0);
  •   第5步:初始化SPI。
/* 針對不同的應用程序,添加需要的底層驅動模塊初始化函數 */
bsp_InitSPIBus();    /* 配置SPI總線 */        
bsp_InitDAC8501(); /* 初始化配置DAC8501 */
  •   第6步:DAC8501驅動主要用到HAL庫的SPI驅動文件,簡單省事些可以添加所有HAL庫C源文件進來。
  •   第7步:應用方法看本章節配套例子即可。

34.9 實驗例程設計框架

通過程序設計框架,讓大家先對配套例程有一個全面的認識,然后再理解細節,本次實驗例程的設計框架如下:

  第1階段,上電啟動階段:

  • 這部分在第14章進行了詳細說明。

  第2階段,進入main函數:

  •  第1部分,硬件初始化,主要是HAL庫,系統時鍾,滴答定時器和LED。
  •  第2部分,應用程序設計部分,實現DAC8501的簡易信號發生器功能。

34.10          實驗例程說明(MDK)

配套例子:

V6-015_DAC8501簡易信號發生器(雙路輸出,16bit分辨率, 0-5V輸出)

實驗目的:

  1. 學習DAC8501的SPI DMA驅動方式實現。

實驗內容:

  1. DAC8501模塊上帶了兩片8501,每片是單通道DAC,片上輸出緩沖運放,軌到軌輸出,16bit分辨率,支持30MHz的SPI時鍾速度。
  2. DAC8501供電電壓2.7-5.5V,模擬輸出帶寬350KHz。

實驗操作:

  1. 啟動一個自動重裝軟件定時器,每100ms翻轉一次LED2。
  2. K1鍵按下,雙通道輸出,通道1輸出方波,通道2輸出正弦波。
  3. K2鍵按下,雙通道輸出方波。
  4. K3鍵按下,雙通道輸出正弦波。
  5. 搖桿OK鍵按下,雙通道輸出直流。

上電后串口打印的信息:

波特率 115200,數據位 8,奇偶校驗位無,停止位 1。

 

波形效果:

 

模塊插入位置:

 

程序設計:

  系統棧大小分配:

 

  硬件外設初始化

硬件外設的初始化是在 bsp.c 文件實現:

/*
*********************************************************************************************************
*    函 數 名: bsp_Init
*    功能說明: 初始化所有的硬件設備。該函數配置CPU寄存器和外設的寄存器並初始化一些全局變量。只需要調用一次
*    形    參:無
*    返 回 值: 無
*********************************************************************************************************
*/
void bsp_Init(void)
{
    /* 
       STM32F429 HAL 庫初始化,此時系統用的還是F429自帶的16MHz,HSI時鍾:
       - 調用函數HAL_InitTick,初始化滴答時鍾中斷1ms。
       - 設置NVIV優先級分組為4。
     */
    HAL_Init();

    /* 
       配置系統時鍾到168MHz
       - 切換使用HSE。
       - 此函數會更新全局變量SystemCoreClock,並重新配置HAL_InitTick。
    */
    SystemClock_Config();

    /* 
       Event Recorder:
       - 可用於代碼執行時間測量,MDK5.25及其以上版本才支持,IAR不支持。
       - 默認不開啟,如果要使能此選項,務必看V5開發板用戶手冊第8章
    */    
#if Enable_EventRecorder == 1  
    /* 初始化EventRecorder並開啟 */
    EventRecorderInitialize(EventRecordAll, 1U);
    EventRecorderStart();
#endif
    
    bsp_InitKey();        /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */
    bsp_InitTimer();      /* 初始化滴答定時器 */
    bsp_InitUart();        /* 初始化串口 */
    bsp_InitExtIO();    /* 初始化擴展IO */
    bsp_InitLed();        /* 初始化LED */    
    BEEP_InitHard();    /* 初始化蜂鳴器 */

    /* 針對不同的應用程序,添加需要的底層驅動模塊初始化函數 */
    bsp_InitSPIBus();    /* 配置SPI總線 */        
    bsp_InitDAC8501();    /* 初始化配置DAC8501 */
}

  主功能:

主程序實現如下操作:

  •   啟動一個自動重裝軟件定時器,每100ms翻轉一次LED4。
  •   K1鍵按下,雙通道輸出,通道1輸出方波,通道2輸出正弦波。
  •   K2鍵按下,雙通道輸出方波。
  •   K3鍵按下,雙通道輸出正弦波。
  •   搖桿OK鍵按下,雙通道輸出直流。
/*
*********************************************************************************************************
*    函 數 名: main
*    功能說明: c程序入口
*    形    參: 無
*    返 回 值: 錯誤代碼(無需處理)
*********************************************************************************************************
*/
int main(void)
{
    bsp_Init();        /* 硬件初始化 */
    
    PrintfLogo();    /* 打印例程名稱和版本等信息 */

    DemoSpiDac();   /* SPI DAC測試 */
}

/*
*********************************************************************************************************
*    函 數 名: DemoSpiDac
*    功能說明: DAC8501測試
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
void DemoSpiDac(void)
{
    uint8_t i=0;
    uint8_t ucKeyCode;    /* 按鍵代碼 */
    
    sfDispMenu();        /* 打印命令提示 */
    
    bsp_StartAutoTimer(0, 200);    /* 啟動1個100ms的自動重裝的定時器 */
    
    
    /* 生成方波數據 */
    for(i =0; i< 50; i++)
    {
        ch1buf[i] = 0;
    }
    
    for(i =50; i< 100; i++)
    {
        ch1buf[i] = 65535;
    }

    /* 生成正弦波數據 */    
    MakeSinTable(ch2buf, 100, 0, 65535);
    
    /* 配置個TIM6中斷,頻率DAC_OUT_FREQ */
    bsp_SetTIMforInt(TIM6, DAC_OUT_FREQ, 2, 0); 
    
    while(1)
    {
        bsp_Idle();        /* 這個函數在bsp.c文件。用戶可以修改這個函數實現CPU休眠和喂狗 */
        
        /* 判斷定時器超時時間 */
        if (bsp_CheckTimer(0))    
        {
            /* 每隔100ms 進來一次 */  
            bsp_LedToggle(4);
        }
        
        /* 按鍵濾波和檢測由后台systick中斷服務程序實現,我們只需要調用bsp_GetKey讀取鍵值即可。 */
        ucKeyCode = bsp_GetKey();    /* 讀取鍵值, 無鍵按下時返回 KEY_NONE = 0 */
        if (ucKeyCode != KEY_NONE)
        {
            switch (ucKeyCode)
            {
                case KEY_DOWN_K1:            /* K1鍵按下,雙通道輸出,通道1輸出方波,通道2輸出正弦波 */
                    /* 生成方波數據 */
                    for(i =0; i< 50; i++)
                    {
                        ch1buf[i] = 0;
                    }
                    
                    for(i =50; i< 100; i++)
                    {
                        ch1buf[i] = 65535;
                    }

                    /* 生成正弦波數據 */    
                    MakeSinTable(ch2buf, 100, 0, 65535);
                    break;

                case KEY_DOWN_K2:            /* K2鍵按下,雙通道輸出方波 */
                    /* 生成方波數據 */
                    for(i =0; i< 50; i++)
                    {
                        ch1buf[i] = 0;
                        ch2buf[i] = 0;
                    }
                    
                    for(i =50; i< 100; i++)
                    {
                        ch1buf[i] = 65535;
                        ch2buf[i] = 65535;
                    }
                    break;

                case KEY_DOWN_K3:            /* K3鍵按下,雙通道輸出正弦波 */
                    MakeSinTable(ch1buf, 100, 0, 65535);
                    MakeSinTable(ch2buf, 100, 0, 65535);
                    break;
                
                case JOY_DOWN_OK:            /* 搖桿OK鍵按下,雙通道輸出直流 */
                    /* 通道1輸出-10V */
                    for(i = 0; i < 100; i++)
                    {
                        ch1buf[i] = 0;
                    }
                    
                    /* 通道2輸出 10V */
                    for(i = 0; i < 100; i++)
                    {
                        ch2buf[i] = 65535;
                    }
                
                    break;
            
                default:
                    /* 其它的鍵值不處理 */
                    break;
            }
        }
    }
}

34.11          實驗例程說明(IAR)

配套例子:

V6-015_DAC8501簡易信號發生器(雙路輸出,16bit分辨率, 0-5V輸出)

實驗目的:

  1. 學習DAC8501的SPI DMA驅動方式實現。

實驗內容:

  1. DAC8501模塊上帶了兩片8501,每片是單通道DAC,片上輸出緩沖運放,軌到軌輸出,16bit分辨率,支持30MHz的SPI時鍾速度。
  2. DAC8501供電電壓2.7-5.5V,模擬輸出帶寬350KHz。

實驗操作:

  1. 啟動一個自動重裝軟件定時器,每100ms翻轉一次LED2。
  2. K1鍵按下,雙通道輸出,通道1輸出方波,通道2輸出正弦波。
  3. K2鍵按下,雙通道輸出方波。
  4. K3鍵按下,雙通道輸出正弦波。
  5. 搖桿OK鍵按下,雙通道輸出直流。

上電后串口打印的信息:

波特率 115200,數據位 8,奇偶校驗位無,停止位 1。

 

波形效果:

 

模塊插入位置:

 

程序設計:

  系統棧大小分配:

 

  硬件外設初始化

硬件外設的初始化是在 bsp.c 文件實現:

/*
*********************************************************************************************************
*    函 數 名: bsp_Init
*    功能說明: 初始化所有的硬件設備。該函數配置CPU寄存器和外設的寄存器並初始化一些全局變量。只需要調用一次
*    形    參:無
*    返 回 值: 無
*********************************************************************************************************
*/
void bsp_Init(void)
{
    /* 
       STM32F407 HAL 庫初始化,此時系統用的還是F407自帶的16MHz,HSI時鍾:
       - 調用函數HAL_InitTick,初始化滴答時鍾中斷1ms。
       - 設置NVIV優先級分組為4。
     */
    HAL_Init();

    /* 
       配置系統時鍾到168MHz
       - 切換使用HSE。
       - 此函數會更新全局變量SystemCoreClock,並重新配置HAL_InitTick。
    */
    SystemClock_Config();

    /* 
       Event Recorder:
       - 可用於代碼執行時間測量,MDK5.25及其以上版本才支持,IAR不支持。
       - 默認不開啟,如果要使能此選項,務必看V5開發板用戶手冊第8章
    */    
#if Enable_EventRecorder == 1  
    /* 初始化EventRecorder並開啟 */
    EventRecorderInitialize(EventRecordAll, 1U);
    EventRecorderStart();
#endif
    
    bsp_InitKey();        /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */
    bsp_InitTimer();      /* 初始化滴答定時器 */
    bsp_InitUart();        /* 初始化串口 */
    bsp_InitExtIO();    /* 初始化擴展IO */
    bsp_InitLed();        /* 初始化LED */    
    BEEP_InitHard();    /* 初始化蜂鳴器 */

    /* 針對不同的應用程序,添加需要的底層驅動模塊初始化函數 */
    bsp_InitSPIBus();    /* 配置SPI總線 */        
    bsp_InitDAC8501();    /* 初始化配置DAC8501 */
}

  主功能:

主程序實現如下操作:

  •   啟動一個自動重裝軟件定時器,每100ms翻轉一次LED4。
  •   K1鍵按下,雙通道輸出,通道1輸出方波,通道2輸出正弦波。
  •   K2鍵按下,雙通道輸出方波。
  •   K3鍵按下,雙通道輸出正弦波。
  •   搖桿OK鍵按下,雙通道輸出直流。
/*
*********************************************************************************************************
*    函 數 名: main
*    功能說明: c程序入口
*    形    參: 無
*    返 回 值: 錯誤代碼(無需處理)
*********************************************************************************************************
*/
int main(void)
{
    bsp_Init();        /* 硬件初始化 */
    
    PrintfLogo();    /* 打印例程名稱和版本等信息 */

    DemoSpiDac();   /* SPI DAC測試 */
}

/*
*********************************************************************************************************
*    函 數 名: DemoSpiDac
*    功能說明: DAC8501測試
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
void DemoSpiDac(void)
{
    uint8_t i=0;
    uint8_t ucKeyCode;    /* 按鍵代碼 */
    
    sfDispMenu();        /* 打印命令提示 */
    
    bsp_StartAutoTimer(0, 200);    /* 啟動1個100ms的自動重裝的定時器 */
    
    
    /* 生成方波數據 */
    for(i =0; i< 50; i++)
    {
        ch1buf[i] = 0;
    }
    
    for(i =50; i< 100; i++)
    {
        ch1buf[i] = 65535;
    }

    /* 生成正弦波數據 */    
    MakeSinTable(ch2buf, 100, 0, 65535);
    
    /* 配置個TIM6中斷,頻率DAC_OUT_FREQ */
    bsp_SetTIMforInt(TIM6, DAC_OUT_FREQ, 2, 0); 
    
    while(1)
    {
        bsp_Idle();        /* 這個函數在bsp.c文件。用戶可以修改這個函數實現CPU休眠和喂狗 */
        
        /* 判斷定時器超時時間 */
        if (bsp_CheckTimer(0))    
        {
            /* 每隔100ms 進來一次 */  
            bsp_LedToggle(4);
        }
        
        /* 按鍵濾波和檢測由后台systick中斷服務程序實現,我們只需要調用bsp_GetKey讀取鍵值即可。 */
        ucKeyCode = bsp_GetKey();    /* 讀取鍵值, 無鍵按下時返回 KEY_NONE = 0 */
        if (ucKeyCode != KEY_NONE)
        {
            switch (ucKeyCode)
            {
                case KEY_DOWN_K1:            /* K1鍵按下,雙通道輸出,通道1輸出方波,通道2輸出正弦波 */
                    /* 生成方波數據 */
                    for(i =0; i< 50; i++)
                    {
                        ch1buf[i] = 0;
                    }
                    
                    for(i =50; i< 100; i++)
                    {
                        ch1buf[i] = 65535;
                    }

                    /* 生成正弦波數據 */    
                    MakeSinTable(ch2buf, 100, 0, 65535);
                    break;

                case KEY_DOWN_K2:            /* K2鍵按下,雙通道輸出方波 */
                    /* 生成方波數據 */
                    for(i =0; i< 50; i++)
                    {
                        ch1buf[i] = 0;
                        ch2buf[i] = 0;
                    }
                    
                    for(i =50; i< 100; i++)
                    {
                        ch1buf[i] = 65535;
                        ch2buf[i] = 65535;
                    }
                    break;

                case KEY_DOWN_K3:            /* K3鍵按下,雙通道輸出正弦波 */
                    MakeSinTable(ch1buf, 100, 0, 65535);
                    MakeSinTable(ch2buf, 100, 0, 65535);
                    break;
                
                case JOY_DOWN_OK:            /* 搖桿OK鍵按下,雙通道輸出直流 */
                    /* 通道1輸出-10V */
                    for(i = 0; i < 100; i++)
                    {
                        ch1buf[i] = 0;
                    }
                    
                    /* 通道2輸出 10V */
                    for(i = 0; i < 100; i++)
                    {
                        ch2buf[i] = 65535;
                    }
                
                    break;
            
                default:
                    /* 其它的鍵值不處理 */
                    break;
            }
        }
    }
}

34.12   總結

本章節涉及到的知識點非常多,需要大家稍花點精力去研究。

 

【STM32F429開發板用戶手冊】


免責聲明!

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



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