出門右轉上一個album入門HAL庫開發 :
連結: 基礎HAL庫ADC採集(上).
連結: 基礎HAL庫ADC採集(中).
連結: 基礎HAL庫ADC採集(下)【轉載】.
STM32的內建ADC:
重要概念:
瞭解:
1.定義一個全域性陣列給到DMA來儲存ADC多路資料:
uint32_t ADC1_Value_DMA[4];
2.start DMA傳輸:
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC1_Value_DMA, 4);//這裡的最後一次引數4是代表有4路
還需要把DMA的中斷註釋掉,否則會一直進中斷
這裡DMA中斷其實沒有用,但CubeMx預設給Enable
3.main里加入校準函數 :
HAL_ADCEx_Calibration_Start(&hadc,0xffffffff);//後面的引數似乎沒有用
【軟體,模擬iic】
MCP3421.h
/*******************Define to prevent recursive inclusion **********/
#ifndef __MCP3421_H__
#define __MCP3421_H__
#ifdef __cplusplus
extern "C" {
#endif
/****************************Includes********************************/
#include "main.h"
#include "port_typ.h"
/****************************定義***********************************/
typedef enum /* 增益 */
{
gain1 = 0x00 ,
gain2 = 0x01 ,
gain4 = 0x02 ,
gain8 = 0x03
}mcp3421_gain_e ;
typedef enum /* 轉換速率 */
{
rate12bit = 0x00 , /* 240SPS */
rate14bit = 0x04 , /* 60SPS */
rate16bit = 0x08 , /* 15SPS */
rate18bit = 0x0C /* 3.75SPS */
}mcp3421_rate_e ;
typedef enum /* 轉換模式 */
{
oneshot_mode = 0x00 , /* 單次轉換模式 */
continuous_mode = 0x10 , /* 連續轉換模式 */
}mcp3421_mode_e;
typedef enum /* 轉換標誌位 */
{
ready = 0x00 , /*0表示轉換結束資料待讀取、*/
nready_or_start = 0x80 , /*1表示轉換正在進行或啟動單次轉換*/
}mcp3421_ready_e ;
/**************************定義結構體*************************************/
/** mcp3421結構體
*
* -address 地址————————————————————預設為 MCP3421_ADDR
* -gain 增益————————————————————預設為1倍增益
【可取1、2、4、8】 @ref mcp3421_gain_e
* -sampling_rate 取樣率————————————預設3.75 SPS (18 bits)
【可取240 SPS (12 bits)、60 SPS (14 bits)、15 SPS (16 bits)】@ref mcp3421_rate_e
* -conversion_mode 轉換模式————————預設One-Shot Conversion
【可取Continuous Conversion、One-Shot Conversion】@ref mcp3421_mode_e
* -ready_flag 狀態標誌位
* 【 0表示轉換結束資料待讀取、1表示轉換正在進行或啟動單次轉換 】@ref mcp3421_ready_e
*/
#define MCP3421_ADDR 0x68
typedef struct
{
uint8_t address ;
uint8_t gain ;
uint8_t sampling_rate ;
uint8_t conversion_mode ;
uint8_t ready_flag ;
}mcp3421_s ;
/*******************************************************
* FunctionName : mcp3421_init()
* Description : 初始化mcp3421,完成iic硬體初始化和mcp3421引數的基本設定
* EntryParameter : mcp mcp3421控制程式碼
* ReturnValue : None
********************************************************/
void mcp3421_init ( mcp3421_s* mcp) ;
/*******************************************************
* FunctionName : mcp3421_write_xxx()
* Description : 修改mcp3421的xxx,在呼叫mcp3421_one_conversion函數時完成引數的正式寫入
* EntryParameter : mcp mcp3421控制程式碼、xxx
* ReturnValue : None
********************************************************/
void mcp3421_write_rate ( mcp3421_s* mcp, uint8_t rate) ;
void mcp3421_write_gain ( mcp3421_s* mcp, uint8_t gain) ;
void mcp3421_write_mode ( mcp3421_s* mcp, uint8_t mode) ;
void mcp3421_write_flag ( mcp3421_s* mcp, uint8_t flag) ;
/*******************************************************
* FunctionName : mcp3421_read_xxx()
* Description : 讀取mcp3421的xxx
* EntryParameter : mcp mcp3421控制程式碼
* ReturnValue : 返回mcp3421的xxx
********************************************************/
uint8_t mcp3421_read_gain ( mcp3421_s* mcp) ;
uint8_t mcp3421_read_rate ( mcp3421_s* mcp) ;
uint8_t mcp3421_read_mode ( mcp3421_s* mcp) ;
uint8_t mcp3421_read_flag ( mcp3421_s* mcp) ;
/*******************************************************
* FunctionName : mcp3421_one_conversion()
* Description : 設定mcp3421為單次轉換並讀取轉換後的資料, 使用mcp中的引數設定mcap3421並開始單次轉換
* EntryParameter : mcp mcp3421控制程式碼
* ReturnValue : 轉換結果,單位為V,範圍-2.048--+(2.048-1LSB)
********************************************************/
float mcp3421_one_conversion( mcp3421_s* mcp) ;
/*******************************************************
* FunctionName : mcp3421_continuous_conversion()
* Description : 設定mcp3421為連續轉換並讀取轉換後的資料,使用mcp中的引數設定mcap3421並開始連續轉換
* EntryParameter : mcp mcp3421控制程式碼
* ReturnValue : 轉換結果,單位為V,範圍-2.048--+(2.048-1LSB)
********************************************************/
void mcp3421_continuous_conversion ( mcp3421_s* mcp, uint8_t times, float *adval) ;
【沒實現呢還^0^】
MCP3421.c
/**************************Includes*************************************/
#include "mcp3421.h"
#include "port_iic.h"
/*************************函數實現************************************/
/* MCP3421初始化 */
void mcp3421_init ( mcp3421_s* mcp)
{
mcp->address = MCP3421_ADDR ;
mcp->gain = gain1 ;
mcp->sampling_rate = rate18bit ;
mcp->conversion_mode = oneshot_mode ;
mcp->ready_flag = nready_or_start ;
iic_init() ;//初始化iic
}
/* 修改增益 */
void mcp3421_write_gain ( mcp3421_s* mcp, uint8_t gain)
{
mcp->gain = gain ;
}
/* 修改取樣率 */
void mcp3421_write_rate ( mcp3421_s* mcp, uint8_t rate)
{
mcp->sampling_rate = rate ;
}
/* 修改轉換模式 */
void mcp3421_write_mode ( mcp3421_s* mcp, uint8_t mode)
{
mcp->conversion_mode = mode ;
}
/* 修改轉換標誌位 */
void mcp3421_write_flag ( mcp3421_s* mcp, uint8_t flag)
{
mcp->ready_flag = flag ;
}
/* 讀取增益 */
uint8_t mcp3421_read_gain ( mcp3421_s* mcp)
{
return mcp->gain ;
}
/* 讀取轉換速率 */
uint8_t mcp3421_read_rate ( mcp3421_s* mcp)
{
return mcp->sampling_rate ;
}
/* 讀取模式 */
uint8_t mcp3421_read_mode ( mcp3421_s* mcp)
{
return mcp->conversion_mode ;
}
/* 讀取標誌位 */
uint8_t mcp3421_read_flag ( mcp3421_s* mcp)
{
return mcp->ready_flag ;
}
/* 獲得MCP3421的單次轉換結果,ad轉換結果,範圍-2.048--+(2.048-1LSB)單位V */
float mcp3421_one_conversion ( mcp3421_s* mcp)
{
uint8_t cofbit =0 ;
uint8_t ad_buf[3] ;
uint32_t temp = 0 ;
float val = 0 ;
mcp->ready_flag = nready_or_start ; //標誌位置1表示轉換正在進行或啟動單次轉換
cofbit = (mcp->gain) | (mcp->sampling_rate) | (mcp->conversion_mode) | (mcp->ready_flag) ; //???
switch (mcp->sampling_rate) //判斷:位數-取樣率
{
case rate12bit : //12bit
iic_master_receive ( mcp->address, cofbit, ad_buf, 2, 100) ;
temp = ( temp << 8) | ad_buf[0] ;
temp = ( temp << 8) | ad_buf[1] ;
temp &= (uint32_t)0x000fff ;
if( (temp >> 11))
{
temp = ~temp ;
val = ( ( temp & (uint32_t)0x000fff) + 1) * 1.0 ;
val = - val ;
}
else
val = temp * 1.0 ;
break ;
case rate14bit : //14bit
iic_master_receive ( mcp->address, cofbit, ad_buf, 2, 100) ;
temp = ( temp << 8) | ad_buf[0] ;
temp = ( temp << 8) | ad_buf[1] ;
temp &= (uint32_t)0x003fff ;
if( (temp >> 13))
{
temp = ~temp ;
val = ( ( temp & (uint32_t)0x003fff) + 1) * 0.250 ;
val = - val ;
}
else
val = temp * 0.250 ;
break ;
case rate16bit : //16bit
iic_master_receive ( mcp->address, cofbit, ad_buf, 2, 100) ;
temp = ( temp << 8) | ad_buf[0] ;
temp = ( temp << 8) | ad_buf[1] ;
temp &= (uint32_t)0x00ffff ;
if( (temp >> 15))
{
temp = ~temp ;
val = ( ( temp & (uint32_t)0x00ffff) + 1) * 0.0625 ;
val = - val ;
}
else
val = temp * 0.0625 ;
break ;
case rate18bit : //18bit
iic_master_receive ( mcp->address, cofbit, ad_buf, 3, 100) ;
temp = ( temp << 8) | ad_buf[0] ;
temp = ( temp << 8) | ad_buf[1] ;
temp = ( temp << 8) | ad_buf[2] ;
temp &= (uint32_t)0x03ffff ;
if( (temp >> 17))
{
temp = ~temp ;
val = ( ( temp & (uint32_t)0x03ffff) + 1) * 0.015625 ;
val = - val ;
}
else
val = temp * 0.015625 ;
break ;
}
switch(mcp->gain) //判斷增益——除以增益還原
{
case gain1 :
val /= 1 ;
break ;
case gain2 :
val /= 2 ;
break ;
case gain4 :
val /= 4 ;
break ;
case gain8 :
val /= 8 ;
break ;
}
return val ;
}
port_iic.h
/******************** Define to prevent recursive inclusion**************/
#ifndef __PORT_IIC_H
#define __PORT_IIC_H
#ifdef __cplusplus
extern "C" {
#endif
/*************************** Includes ***********************************/
#include "main.h"
#include "port_typ.h"
/*******************************************************
* FunctionName : mcp3421_init()
* Description : 初始化iic【無具體實現~擺設】
* EntryParameter : None
* ReturnValue : None
********************************************************/
void iic_init (void) ;
/*******************************************************
* FunctionName : mcp3421_init()
* Description : iic主機寫資料,向指定從裝置的暫存器寫入一定數量的資料
* EntryParameter :
* @param[in] dev 從裝置號
* @param[in] reg 暫存器地址
* @param[in] str 指向帶寫入資料的指標
* @param[in] length 資料長度
* @param[in] timeout 單個資料寫入的超時時間
* ReturnValue :
* -0 寫成功
* -other 第i個字元寫入時出錯
********************************************************/
uint8_t iic_master_transmit ( uint8_t dev, uint8_t reg, uint8_t *str, uint16_t length, uint32_t timeout) ;
/*******************************************************
* FunctionName : mcp3421_init()
* Description : iic主機讀資料,從指定從裝置的暫存器讀出一定數量的資料
* EntryParameter :
* @param[in] dev 從裝置號
* @param[in] reg 暫存器地址
* @param[in] str 接收資料指標
* @param[in] length 資料長度
* @param[in] timeout 單個資料讀取的超時時間
* ReturnValue :
* -0 寫成功
* -other 第i個字元寫入時出錯
********************************************************/
uint8_t iic_master_receive ( uint8_t dev, uint8_t reg, uint8_t *str, uint16_t length, uint32_t timeout) ;
port_iic.c
在main.h裡定義 SDA SCL的GPIO 宏定義
#define MCP3421_SDA_Pin GPIO_PIN_11
#define MCP3421_SDA_GPIO_Port GPIOA
#define MCP3421_SCL_Pin GPIO_PIN_12
#define MCP3421_SCL_GPIO_Port GPIOA
/*************************** Includes ***********************************/
#include "port_iic.h"
#include "port_delay.h"
#include "gpio.h"
/*************************** 宏定義 ***********************************/
#define I2C_DELAY_US(x) port_delay_us(x)
#define I2C_DELAY_MS(x) port_delay_ms(x)
#define I2C_SCL_SET() HAL_GPIO_WritePin( GPIOA, MCP3421_SCL_Pin, GPIO_PIN_SET)
#define I2C_SCL_RESET() HAL_GPIO_WritePin( GPIOA, MCP3421_SCL_Pin, GPIO_PIN_RESET)
#define I2C_SDA_SET() HAL_GPIO_WritePin( GPIOA, MCP3421_SDA_Pin, GPIO_PIN_SET)
#define I2C_SDA_RESET() HAL_GPIO_WritePin( GPIOA, MCP3421_SDA_Pin, GPIO_PIN_RESET)
#define I2C_SDA_GET() HAL_GPIO_ReadPin( GPIOA, MCP3421_SDA_Pin)
#define I2C_SDA_IN() {GPIOA->CRH&=0XFFFF0FFF;GPIOA->CRH|=0X00008000;} /* PA11輸入模式 */
#define I2C_SDA_OUT() {GPIOA->CRH&=0XFFFF0FFF;GPIOA->CRH|=0X00003000;} /* PA11輸出模式 */
/*************************** 使用者自定義變數 ***********************************/
uint8_t iic_txbuf[32] ;
/*******************************************************
* Description : 傳送iic起始訊號
********************************************************/
static void iic_start()
{
/* 當 SCL 高電平時,SDA 出現一個下跳沿表示 I2C 匯流排啟動訊號 */
I2C_SDA_OUT() ;
I2C_SDA_SET() ;
I2C_SCL_SET() ;
I2C_DELAY_US(4) ;
I2C_SDA_RESET() ;
I2C_DELAY_US(4) ;
I2C_SCL_RESET() ;
}
/*******************************************************
* Description : iic傳送結束訊號
********************************************************/
static void iic_stop()
{
/* 當 SCL 高電平時,SDA 出現一個上跳沿表示 I2C 匯流排停止訊號 */
I2C_SDA_OUT() ;
I2C_SCL_RESET() ;
I2C_SDA_RESET() ;
I2C_DELAY_US(4) ;
I2C_SCL_SET() ;
I2C_SDA_SET() ;
I2C_DELAY_US(4) ;
}
/*******************************************************
* Description : 傳送一個位元組
********************************************************/
static void iic_send_byte (uint8_t tx)
{
uint8_t i ;
I2C_SDA_OUT() ;
I2C_SCL_RESET() ;
for ( i = 0; i < 8; i++)
{
if ( tx & 0x80)
{
I2C_SDA_SET() ;
}
else
{
I2C_SDA_RESET() ;
}
tx <<= 1 ;
I2C_DELAY_US(2) ;
I2C_SCL_SET() ;
I2C_DELAY_US(2) ;
I2C_SCL_RESET() ;
I2C_DELAY_US(2) ;
}
}
/*******************************************************
* Description : iic讀一個位元組
********************************************************/
static uint8_t iic_read_byte()
{
uint8_t i ;
uint8_t res ;
res = 0 ;
I2C_SDA_IN() ;
for ( i = 0; i < 8; i++)
{
I2C_SCL_RESET() ;
I2C_DELAY_US(2) ;
I2C_SCL_SET() ;
res <<= 1 ;
if ( I2C_SDA_GET())
{
res++ ;
}
I2C_DELAY_US(1) ;
}
return res ;
}
/*******************************************************
* Description : iic等待應答訊號
********************************************************/
static uint8_t iic_wait_ack()
{
uint8_t i ;
I2C_SDA_IN() ;
I2C_SDA_SET() ;
I2C_DELAY_US(1) ;
I2C_SCL_SET() ;
I2C_DELAY_US(1) ;
while ( I2C_SDA_GET())
{
i++ ;
if ( i > 250)
{
iic_stop() ;
return 1 ;
}
}
I2C_SCL_RESET() ;
return 0 ;
}
/*******************************************************
* Description : iic傳送應答訊號
********************************************************/
static void iic_send_ack()
{
I2C_SCL_RESET() ;
I2C_SDA_OUT() ;
I2C_SDA_RESET() ;
I2C_DELAY_US(2) ;
I2C_SCL_SET() ;
I2C_DELAY_US(2) ;
I2C_SCL_RESET() ;
}
static void iic_send_nack()
{
I2C_SCL_RESET() ;
I2C_SDA_OUT() ;
I2C_SDA_SET() ;
I2C_DELAY_US(2) ;
I2C_SCL_SET() ;
I2C_DELAY_US(2) ;
I2C_SCL_RESET() ;
}
/*******************************************************
* Description : 拷貝函數
從源記憶體地址的起始位置開始拷貝若干個位元組到目標記憶體地址中,即從源source中拷貝n個位元組到目標destin中。
********************************************************/
static void iic_memcpy ( uint8_t *dest, uint8_t *src, uint32_t length)
{
uint32_t i ;
for ( i = 0; i < length; i++)
{
*dest = *src ;
dest++ ;
src++ ;
}
}
/*******************************************************
* Description : iic初始化【擺個樣子】
********************************************************/
void iic_init()
{
}
/*******************************************************
* Description : iic主機寫 資料
返回0寫成功,返回其他,則在寫第i個資料的時候超時
********************************************************/
uint8_t iic_master_transmit ( uint8_t dev, uint8_t reg, uint8_t *str, uint16_t length, uint32_t timeout)
{
uint16_t i ;
uint32_t j ;
uint8_t rev ;
rev = 0 ;
iic_txbuf[0] = ( ( dev << 1) | 0) ;
iic_txbuf[1] = reg ;
iic_memcpy ( &(iic_txbuf[2]), str, length) ;
length += 2 ;
iic_start() ;
for ( i = 0; i < length; i++)
{
iic_send_byte(iic_txbuf[i]) ;
j = 0 ;
while ( ( iic_wait_ack()) && ( j < timeout))
{
j++ ;
I2C_DELAY_US(5) ;
}
if ( j >= timeout)
{
rev = i + 1 ;
break ;
}
}
iic_stop() ;
return rev ;
}
/*******************************************************
* Description : iic主機讀 資料
返回0寫成功,返回其他,則在寫第i個資料的時候超時
********************************************************/
uint8_t iic_master_receive ( uint8_t dev, uint8_t reg, uint8_t *str, uint16_t length, uint32_t timeout)
{
uint16_t i = 0 ;
iic_start() ;
iic_send_byte ( ( dev << 1) | 0) ;
if( iic_wait_ack())
{
iic_stop() ;
return 1 ;
}
iic_send_byte(reg) ;
if( iic_wait_ack())
{
iic_stop() ;
return 1 ;
}
iic_start() ;
iic_send_byte( ( dev << 1) | 1) ;
if( iic_wait_ack())
{
iic_stop() ;
return 1 ;
}
length-- ;
for ( ; i < length; i++)
{
str[i] = iic_read_byte() ;
iic_send_ack() ;
}
str[i] = iic_read_byte() ;
iic_send_nack() ;
iic_stop() ;
return 0 ;
}
port_delay.h
提供毫秒和微妙級別的軟體延時:
/************Define to prevent recursive inclusion ******/
#ifndef __PORT_DELAY_H
#define __PORT_DELAY_H
#ifdef __cplusplus
extern "C" {
#endif
/*****************Includes******************/
#include "main.h"
#include "port_typ.h"
/*****************微妙延時*****************/
void port_delay_us( uint32_t us) ;
/*****************毫秒延時*****************/
void port_delay_ms( uint32_t ms) ;
port_delay.h
/*****************Includes******************/
#include "port_delay.h"
#include "tim.h"
/*******************************************************
* Description : 微妙延時
********************************************************/
void port_delay_us( uint32_t us)
{
uint32_t differ = 0xfff0 - us ;
HAL_TIM_Base_Start(&htim4) ;
__HAL_TIM_SET_COUNTER( &htim4, differ) ;
while( differ < 0xfff0)
{
differ = __HAL_TIM_GET_COUNTER(&htim4) ;
}
HAL_TIM_Base_Stop(&htim4) ;
}
/*******************************************************
* Description : 毫秒延時
********************************************************/
void port_delay_ms( uint32_t ms)
{
HAL_Delay(ms) ;
}
①在main中初始化
mcp3421_init(&mcp) ; // 初始化MCP3421---有預設值~18位元
②在其他的任務中呼叫
float voltage1 ;//全域性變數
voltage1 = mcp3421_one_conversion(&mcp) ;
/*******************************************************
* Description : 讀取adc轉換結果,阻塞式輪詢實現,必須實現
********************************************************/
float port_adc_get_vaule(void)
{
float rev = 0 ;
/* 單次轉換+DMA傳輸+內部參考電壓校準資料 */
HAL_ADC_Start_DMA( &hadc1, (uint32_t*)port_adc_buf, 2) ;
port_delay_ms(1) ;
rev = ( ( 1.225 * port_adc_buf[0]) / port_adc_buf[1]) ;
return rev ;
}
/*******************************************************
* Description : 採集八次做平均濾波
********************************************************/
float port_ad
float av_filter_get_ad()
{
uint8_t j ;
port_ad = 0 ; /* 重灌在adc值 */
port_adc_get_vaule() ; /* 捨去第一次啟動adc採集到的值 */
for ( j = 0; j < 8; j++)
{
port_ad += port_adc_get_vaule() ; /* 採集八次做平均濾波 */
}
port_ad /= 8 ;
return port_ad;
}
/* 應程式初始化 */
void my_app_init()
{
temp_init() ; /* 初始化溫度感測器 */
port_adc_init() ; /* 初始化adc ---其實已經在hal庫初始了 */
}
/* 應用程式 */
void my_app()
{
uint8_t j ;
port_ad = 0 ; /* 重灌在adc值 */
port_adc_get_vaule() ; /* 捨去第一次啟動adc採集到的值 */
for ( j = 0; j < 8; j++)
{
port_ad += port_adc_get_vaule() ; /* 採集八次做平均濾波 */
}
port_ad /= 8 ;
tep = temp_get_temp( port_ad*1000) ; /* 轉換成mv */
pr_info("%s:%d",TAG,tep) ; /* 列印溫度,放大了100倍 */
port_delay_ms(500) ;
}
int main(void)
{
my_app_init() ;
while (1)
{
my_app() ;
}
}
/* 應程式初始化 */
void my_app_init()
{
mcp3421_init(&mcp) ; /* 初始化MCP3421 */
temp_init() ; /* 初始化溫度感測器 */
}
/* 應用程式 */
void my_app()
{
voltage1 = mcp3421_one_conversion(&mcp) ;
tep = temp_get_temp( voltage1) ;
pr_info("%s:%d",TAG,tep) ; /* 列印溫度,放大了100倍 */
port_delay_ms(1000) ;
}
int main(void)
{
my_app_init() ;
while (1)
{
my_app() ;
}
}