STM8L051之通過ADC1與DMA讀取內部參考電壓,求取VDD電源電壓---庫函數版

    stm8L051芯片內部的參考電壓與電源電壓有一定的關係,

這在芯片供電電壓變化的情況下,測量外部ADC電壓輸入
提供一個確定的參考電壓。這裏提前釐清下:該內部參考
電壓VREFINT 並非ADC 的參考電壓,ADC 的參考電壓依
然是VDD。即使VDD 有所波動,這個VREFINT 電壓恆定
不變,對於ADC 電路而言,它只是個測試點。
對於某固定的ADC 參考電壓情況下,所有被測電壓點的
AD轉換值與該點電壓值保持同一比例關係,換句話說,
對於ADC參考電壓固定情況下,各點的電壓與ADC值與成
線性關係。下面圖形是芯片分別在3個不同參考電壓的示意
圖,這裏參考電壓接VDD。下面三根斜線分別是VDD 爲2.8V
、3.2V、3.6V 時的AD轉換曲線示意圖。那根黃色垂直虛線是
表示內部VREFINT電壓(1.22V)所在的位置。
這裏寫圖片描述
圖片以及部分文字是引用網友的原話,如果需要我備註的請給我提醒一下
剛開始的時候我是直接操作寄存器,但無奈怎樣讀測
不準,計算值同實際電源電壓差別比較大,後來不得
已才用庫函數試試。效果還可以,能測量電源的電壓,
當然stm8L芯片內部已經有一個出廠時寫好的校準值,
程序中可以讀取,這裏我只用手冊中(技術手冊中比編
程手冊說的詳細一點),的典型值1.224V。下面是相
關的代碼(參考固件庫的adc與dma例程):

#include "adc.h"
#include "led.h"
uint16_t Buffer[BUFFER_SIZE]  = {0};
uint32_t Verfin = 0;//電源電壓*1000
void ADC_Config(void)
{
  /* Enable ADC1 clock */
  CLK_PeripheralClockConfig(CLK_Peripheral_ADC1, ENABLE);
/* Initialize and configure ADC1 */
  ADC_Init(ADC1, ADC_ConversionMode_Single, ADC_Resolution_12Bit, ADC_Prescaler_1);
  ADC_SamplingTimeConfig(ADC1, ADC_Group_SlowChannels, ADC_SamplingTime_24Cycles);
  ADC_SamplingTimeConfig(ADC1, ADC_Group_FastChannels, ADC_SamplingTime_24Cycles);

  /* Enable ADC1 */
  ADC_Cmd(ADC1, ENABLE);
  ADC_VrefintCmd(ENABLE);

  /* Enable ADC1 Channels 3 */
  ADC_ChannelCmd(ADC1, ADC_Channel_3, ENABLE); /* connected to Potentiometer RV */
  /* Enable ADC1 Channels 24 */
  ADC_ChannelCmd(ADC1, ADC_Channel_Vrefint, ENABLE); /* connected to ADC_Channel_Vrefint */

}
void DMA_Config(void)
{
   /* Enable DMA1 clock */
  CLK_PeripheralClockConfig(CLK_Peripheral_DMA1, ENABLE);
  /* Connect ADC to DMA channel 0 */
 SYSCFG_REMAPDMAChannelConfig(REMAP_DMA1Channel_ADC1ToChannel0);//ADC通道要remap
//BUFFER_SIZE
  DMA_Init(DMA1_Channel0, BUFFER_ADDRESS,
           ADC1_DR_ADDRESS,
           BUFFER_SIZE,
           DMA_DIR_PeripheralToMemory,
           DMA_Mode_Circular,
           DMA_MemoryIncMode_Inc,
           DMA_Priority_High,
           DMA_MemoryDataSize_HalfWord);
  /* DMA Channel0 enable */
  DMA_Cmd(DMA1_Channel0, ENABLE);
  /* Enable DMA1 channel0 Transfer complete interrupt */
  DMA_ITConfig(DMA1_Channel0, DMA_ITx_TC, ENABLE);   
  /* DMA enable */
  DMA_GlobalCmd(ENABLE);
  ADC_DMACmd(ADC1, ENABLE); 
}
/**
  * @brief DMA1 channel0 and channel1 Interrupt routine.
  * @param  None
  * @retval None
  */
INTERRUPT_HANDLER(DMA1_CHANNEL0_1_IRQHandler, 2)
{
  /* In order to detect unexpected events during development,
     it is recommended to set a breakpoint on the following instruction.
  */
  /* Calculate Potentiometer RV voltage value*/
 // Voltage = (uint32_t)((uint32_t)Buffer[0] * //(uint32_t)ADC_RATIO) / 1000;

  /* Calculate BNC voltage value*/
   //(uint32_t)((uint32_t)Buffer[1] * 1225) / 1000;
  Verfin =  (uint32_t)1224*4096/Buffer[1];

  //GPIO_ToggleBits(GPIOB, GPIO_Pin_4);
  /* Clear IT Pending Bit */
  DMA_ClearITPendingBit(DMA1_IT_TC0);
}

上面時,c中的代碼,。h中的如下:

ifndef __ADC_H
#define __ADC_H
#include "stm8l15x.h"
//#include "stm8l15x_it.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define ADC1_DR_ADDRESS        ((uint16_t)0x5344)
#define BUFFER_SIZE            ((uint8_t) 0x02)
#define BUFFER_ADDRESS         ((uint16_t)(&Buffer))
extern uint16_t Buffer[BUFFER_SIZE];
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
void ADC_Config(void);
void DMA_Config(void);
#endif

下面是main中的代碼:

#include "bsp.h"



int main( void )
{
  SysInit();//bsp文件中包含了系統,adc與dma的初始化
/* Enable Interrupts */
  enableInterrupts();
  ADC_SoftwareStartConv(ADC1);//START,necessary 啓動adc轉換
  while(1)
  {

  }
  return 0;
}

這裏寫圖片描述
從調試窗口中看到,Verfin = 2498,實際萬用表測
的電壓=2.49V,可見測量的數據還是挺準確的,另
外在3點多V電源情況測的值也基本準確。

最後,由於stm8L051的內存空間比較小,
還是希望能寄存器開發,這等待有空再參
考庫函數研究測量內部參考電壓的寄存器操作吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章