21.01_TMP-ADC采样内部温度传感器数据
测试步骤
使用软件触发ADC1采样温度传感器并计算温度
实测数据
tmp = 218
参考代码
21.01_TMP_TempSenseADC.c
/**
* @brief TMP-ADC采样内部温度传感器数据
* @details 使用软件触发ADC1采样温度传感器并计算温度
*/
#include "lks32mc09x_lib.h"
volatile int32_t tmp = 0;
/**
* @brief 主函数
*/
int main(void)
{
ADC_InitTypeDef ADC_InitStruct;
// 初始化ADC结构体
ADC_StructInit(&ADC_InitStruct);
// 配置ADC参数
ADC_InitStruct.IE = ADC_IE_SF1; // 禁用中断
ADC_InitStruct.RE = 0; // 禁用DMA请求
ADC_InitStruct.NSMP = 0; // 禁用两段采样
ADC_InitStruct.DATA_ALIGN = 0; // 右对齐
ADC_InitStruct.CSMP = 0; // 禁用连续采样
ADC_InitStruct.TCNT = 0; // 触发一次采样
ADC_InitStruct.TROVS = 0; // 禁用过采样
ADC_InitStruct.OVSR = 0; // 过采样率
ADC_InitStruct.TRIG = 0; // MCPWM0 T0 事件触发 ADC 常规采样
ADC_InitStruct.S1 = 1; // 第一段常规采样次数
ADC_InitStruct.S2 = 0; // 第二段常规采样次数
ADC_InitStruct.IS1 = 0; // 空闲采样次数
ADC_InitStruct.GAIN = ADC_GAIN_3V6; // 3.6V量程
ADC_InitStruct.LTH = 0; // 禁用模拟看门狗
ADC_InitStruct.HTH = 0xFFFF; // 禁用模拟看门狗
ADC_InitStruct.GEN = 0; // 禁用模拟看门狗
ADC_InitStruct.IDLE_PRI = 0;
ADC_Init(ADC1, &ADC_InitStruct);
ADC_SetChn(ADC1, ADC_DAT_0, ADC1_CHN_TMP);
TMP_Init();
while (1)
{
ADC_ClearIRQFlag(ADC1, ADC_IF_SF1);
ADC_SoftTrig(ADC1);
while (ADC_GetIRQFlag(ADC1, ADC_IF_SF1) == 0)
;
tmp = TMP_GetCurrentTemperature(ADC_GetConversionValue(ADC1, ADC_DAT_0)); // 将ADC采样值转换为温度值并保存到全局变量CurrentTempature中
}
}
使用到的库函数
库函数部分代码
#define ADC0 ((ADC_TypeDef *)ADC0_BASE)
#define ADC0_CFG_DATA_ALIGN_BIT BIT10
#define ADC0_CHN0_PDS0(x) (uint32_t)(((x) & 0xF) << ADC0_CHN0_PDS0_POS)
#define ADC0_CHN0_PDS1(x) (uint32_t)(((x) & 0xF) << ADC0_CHN0_PDS1_POS)
#define ADC0_CHN0_PDS2(x) (uint32_t)(((x) & 0xF) << ADC0_CHN0_PDS2_POS)
#define ADC0_CHN0_PDS3(x) (uint32_t)(((x) & 0xF) << ADC0_CHN0_PDS3_POS)
#define ADC0_CHN1_PDS4(x) (uint32_t)(((x) & 0xF) << ADC0_CHN1_PDS4_POS)
#define ADC0_CHN1_PDS5(x) (uint32_t)(((x) & 0xF) << ADC0_CHN1_PDS5_POS)
#define ADC0_CHN1_PDS6(x) (uint32_t)(((x) & 0xF) << ADC0_CHN1_PDS6_POS)
#define ADC0_CHN1_PDS7(x) (uint32_t)(((x) & 0xF) << ADC0_CHN1_PDS7_POS)
#define ADC0_CHN2_PDS10(x) (uint32_t)(((x) & 0xF) << ADC0_CHN2_PDS10_POS)
#define ADC0_CHN2_PDS11(x) (uint32_t)(((x) & 0xF) << ADC0_CHN2_PDS11_POS)
#define ADC0_CHN2_PDS8(x) (uint32_t)(((x) & 0xF) << ADC0_CHN2_PDS8_POS)
#define ADC0_CHN2_PDS9(x) (uint32_t)(((x) & 0xF) << ADC0_CHN2_PDS9_POS)
#define ADC1 ((ADC_TypeDef *)ADC1_BASE)
#define NVR_ADDR_ADC_0_AMC0 0x00001424
#define NVR_ADDR_ADC_0_AMC1 0x0000142C
#define NVR_ADDR_ADC_0_DC0 0x00001420
#define NVR_ADDR_ADC_0_DC1 0x00001428
#define NVR_ADDR_ADC_1_AMC0 0x00001434
#define NVR_ADDR_ADC_1_AMC1 0x0000143C
#define NVR_ADDR_ADC_1_DC0 0x00001430
#define NVR_ADDR_ADC_1_DC1 0x00001438
#define NVR_ADDR_TMP_B 0x000014D4
#define NVR_ADDR_TMP_K 0x000014D0
#define REG_READ(reg) (reg)
#define REG_READ_BIT(reg,mask) ((reg) & (mask))
#define REG_READ_BIT_POS_MASK(reg,mask) (((reg) & (mask##_MASK)) >> mask##_POS)
#define REG_RESET(reg,mask) reg &= ~(mask)
#define REG_SET(reg,mask) reg |= (mask)
#define REG_WRITE(reg,mask) reg = (mask)
#define REG_WRITE_BIT(reg,mask,val) reg = ((reg) & ~(mask)) | (val)
#define SYS0 ((SYS_TypeDef *)(SYS_BASE))
#define SYS_MODULE_ADC0 BIT22
#define SYS_MODULE_ADC1 BIT23
/**
* @brief ADC初始化结构体定义
*/
typedef struct ADC_InitTypeDef {
uint16_t IE;
uint16_t RE;
uint16_t NSMP;
uint16_t DATA_ALIGN;
uint16_t CSMP;
uint16_t TCNT;
uint16_t TROVS;
uint16_t OVSR;
uint32_t TRIG;
uint16_t S1;
uint16_t S2;
uint16_t IS1;
uint16_t GAIN;
uint16_t LTH;
uint16_t HTH;
uint16_t GEN;
uint16_t IDLE_PRI;
};
/**
* @brief ADC数据寄存器序号枚举定义
*/
typedef enum ADC_DAT_x {
ADC_DAT_0 = 0,
ADC_DAT_1 = 1,
ADC_DAT_2 = 2,
ADC_DAT_3 = 3,
ADC_DAT_4 = 4,
ADC_DAT_5 = 5,
ADC_DAT_6 = 6,
ADC_DAT_7 = 7,
ADC_DAT_8 = 8,
ADC_DAT_9 = 9,
ADC_DAT_10 = 10,
ADC_DAT_11 = 11,
}} {enum_name};
/**
* @brief ADC采样通道序号枚举定义
*/
typedef enum ADC_CHN_x {
ADC_CHN_0 = 0,
ADC_CHN_1 = 1,
ADC_CHN_2 = 2,
ADC_CHN_3 = 3,
ADC_CHN_4 = 4,
ADC_CHN_5 = 5,
ADC_CHN_6 = 6,
ADC_CHN_7 = 7,
ADC_CHN_8 = 8,
ADC_CHN_9 = 9,
ADC_CHN_10 = 10,
ADC_CHN_11 = 11,
ADC_CHN_12 = 12,
ADC_CHN_13 = 13,
ADC_CHN_14 = 14,
ADC_CHN_15 = 15,
ADC0_CHN_OPA0 = 0,
ADC0_CHN_OPA1 = 1,
ADC0_CHN_OPA2 = 2,
ADC0_CHN_OPA3 = 3,
ADC0_CHN_ADC01_CH4 = 4,
ADC0_CHN_ADC01_CH5 = 5,
ADC0_CHN_ADC01_CH6 = 6,
ADC0_CHN_ADC01_CH7 = 7,
ADC0_CHN_ADC0_CH8 = 8,
ADC0_CHN_REF24 = 9,
ADC0_CHN_ADC01_CH10 = 10,
ADC0_CHN_ADC01_CH11 = 11,
ADC0_CHN_ADC0_CH12 = 12,
ADC0_CHN_ADC0_CH13 = 13,
ADC0_CHN_DAC = 14,
ADC0_CHN_AVSS = 15,
ADC1_CHN_OPA0 = 0,
ADC1_CHN_OPA1 = 1,
ADC1_CHN_OPA2 = 2,
ADC1_CHN_OPA3 = 3,
ADC1_CHN_ADC01_CH4 = 4,
ADC1_CHN_ADC01_CH5 = 5,
ADC1_CHN_ADC01_CH6 = 6,
ADC1_CHN_ADC01_CH7 = 7,
ADC1_CHN_ADC1_CH8 = 8,
ADC1_CHN_ADC1_CH9 = 9,
ADC1_CHN_ADC01_CH10 = 10,
ADC1_CHN_ADC01_CH11 = 11,
ADC1_CHN_ADC1_CH12 = 12,
ADC1_CHN_ADC1_CH13 = 13,
ADC1_CHN_TMP = 14,
ADC1_CHN_AVDD = 15,
}} {enum_name};
/**
* @brief 使能ADC模块
* @param ADCx: ADC模块指针,指向ADC0或ADC1
*/
void ADC_Enable(ADC_TypeDef *ADCx)
{
REG_WRITE(SYS0->PROTECT, 0x7a83);
// 使能ADC模块时钟
REG_SET(SYS0->AFE_REG7, BIT8 | BIT9);
REG_WRITE(SYS0->PROTECT, 0);
}
/**
* @brief 使能温度传感器
*/
void TMP_Enable(void)
{
SYS_WR_PROTECT = 0x7a83;
SYS_AFE_REG5 |= BIT3;
SYS_WR_PROTECT = 0;
}
/**
* @brief 初始化ADC模块
* @param ADCx: ADC模块指针,指向ADC0或ADC1
* @param ADC_InitStruct: 指向ADC初始化结构体的指针
*/
void ADC_Init(ADC_TypeDef *ADCx, ADC_InitTypeDef *ADC_InitStruct)
{
ADC_Enable(ADCx);
SYS_ModuleClockCmd(SYS_MODULE_ADC0, 1);
SYS_ModuleClockCmd(SYS_MODULE_ADC1, 1);
if (ADC_InitStruct->S2 == 0)
{
ADC_InitStruct->NSMP = DISABLE; // 当第二段采样次数为0时,不允许配置第二段使能
}
// 解锁SYS寄存器
REG_WRITE(SYS0->PROTECT, 0x7a83);
// 配置ADC初始化结构体中的各个成员
REG_WRITE(ADCx->IE, ADC_InitStruct->IE | ADC_InitStruct->RE);
// 计算并一次性配置CFG寄存器
REG_WRITE(ADCx->CFG, ((ADC_InitStruct->NSMP << 12) |
(1 << 11) | // 初始化时复位adc状态机
(ADC_InitStruct->DATA_ALIGN << 10) |
(ADC_InitStruct->IDLE_PRI << 9) |
(ADC_InitStruct->CSMP << 8) |
(ADC_InitStruct->TCNT << 4) |
(ADC_InitStruct->TROVS << 3) |
(ADC_InitStruct->OVSR << 0)));
REG_WRITE(ADCx->TRIG, ADC_InitStruct->TRIG);
// 配置CHNT寄存器
REG_WRITE(ADCx->CHNT, (REG_READ(ADCx->CHNT) & ~((0x0F << 0) | (0x0F << 4) | (0x0F << 8))) |
((ADC_InitStruct->S1 << 0) |
(ADC_InitStruct->S2 << 4) |
(ADC_InitStruct->IS1 << 8)));
// 配置GAIN寄存器
REG_WRITE_BIT(ADCx->GAIN, 1 << 0, ADC_InitStruct->GAIN << 0);
REG_WRITE(ADCx->LTH, ADC_InitStruct->LTH);
REG_WRITE(ADCx->HTH, ADC_InitStruct->HTH);
REG_WRITE(ADCx->GEN, ADC_InitStruct->GEN);
if (ADCx == ADC0)
{
REG_WRITE(ADCx->AMC0, TRIM_Read(NVR_ADDR_ADC_0_AMC0));
REG_WRITE(ADCx->DC0, TRIM_Read(NVR_ADDR_ADC_0_DC0));
REG_WRITE(ADCx->AMC1, TRIM_Read(NVR_ADDR_ADC_0_AMC1));
REG_WRITE(ADCx->DC1, TRIM_Read(NVR_ADDR_ADC_0_DC1));
}
else if (ADCx == ADC1)
{
REG_WRITE(ADCx->AMC0, TRIM_Read(NVR_ADDR_ADC_1_AMC0));
REG_WRITE(ADCx->DC0, TRIM_Read(NVR_ADDR_ADC_1_DC0));
REG_WRITE(ADCx->AMC1, TRIM_Read(NVR_ADDR_ADC_1_AMC1));
REG_WRITE(ADCx->DC1, TRIM_Read(NVR_ADDR_ADC_1_DC1));
}
else
{
__NOP();
}
}
/**
* @brief 初始化温度传感器
*/
void TMP_Init(void)
{
tmp_k = TRIM_Read(NVR_ADDR_TMP_K);
tmp_b = TRIM_Read(NVR_ADDR_TMP_B);
TMP_Enable();
}
/**
* @brief 将ADC初始化结构体置为默认值
* @param ADC_InitStruct: 指向ADC初始化结构体的指针
*/
void ADC_StructInit(ADC_InitTypeDef *ADC_InitStruct)
{
for (int i = 0; i < sizeof(ADC_InitTypeDef) / sizeof(uint16_t); i++)
{
((uint16_t *)ADC_InitStruct)[i] = 0;
}
}
/**
* @brief 执行软件触发ADC采样,采样次数取决于ADC_InitTypeDef里的S1的配置
* @param ADCx: ADC模块指针,指向ADC0或ADC1
*/
void ADC_SoftTrig(ADC_TypeDef *ADCx)
{
// 写入软件触发值
REG_WRITE(ADCx->SWT, 0x5AA5);
}
/**
* @brief 数字模块时钟使能
* @param nModule 模块编号
* @param state 使能或禁用状态
*/
void SYS_ModuleClockCmd(uint32_t nModule, uint8_t state)
{
REG_WRITE(SYS0->PROTECT, 0x7a83);
if (state)
{
REG_SET(SYS0->CLK_FEN, nModule);
}
else
{
REG_RESET(SYS0->CLK_FEN, nModule);
}
REG_WRITE(SYS0->PROTECT, 0);
}
/**
* @brief 清除ADC中断标志位
* @param ADCx: ADC模块指针,指向ADC0或ADC1
* @param INT_flag: 中断标志位,可以是ADC_IF_ISF等
*/
void ADC_ClearIRQFlag(ADC_TypeDef *ADCx, uint16_t INT_flag)
{
REG_WRITE(ADCx->IF, INT_flag);
}
/**
* @brief 获取ADC中断标志位状态
* @param ADCx: ADC模块指针,指向ADC0或ADC1
* @param INT_flag: 中断标志位,可以是ADC_IF_ISF等
* @return 中断标志位状态
*/
uint16_t ADC_GetIRQFlag(ADC_TypeDef *ADCx, uint16_t INT_flag)
{
return REG_READ_BIT(ADCx->IF, INT_flag) ? 1 : 0;
}
/**
* @brief 获取ADC通道的转换值
* @param ADCx: ADC模块指针,指向ADC0或ADC1
* @param DATNum: 数据寄存器序号,如ADC_DAT_0
* @return 转换值
*/
s16 ADC_GetConversionValue(ADC_TypeDef *ADCx, ADC_DAT_x DATNum)
{
int32_t adc_dat = ADC_GetConversionValueS32(ADCx, DATNum);
// adc_dat不会小于-32767,这里不做判断
if (adc_dat > 32767)
{
adc_dat = 32767;
}
return adc_dat;
}
/**
* @brief 获取ADC通道的转换值(按int32返回,采样通道4、5、6、7时,返回值大于32767)
* @param ADCx: ADC模块指针,指向ADC0或ADC1
* @param DATNum: 数据寄存器序号,如ADC_DAT_0
* @return 转换值
*/
int32_t ADC_GetConversionValueS32(ADC_TypeDef *ADCx, ADC_DAT_x DATNum)
{
int32_t adc_dat = 0;
uint16_t adc_chn = 0;
switch (DATNum)
{
case ADC_DAT_0:
adc_dat = REG_READ(ADCx->DAT0);
adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN0, ADC0_CHN0_PDS0);
break;
case ADC_DAT_1:
adc_dat = REG_READ(ADCx->DAT1);
adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN0, ADC0_CHN0_PDS1);
break;
case ADC_DAT_2:
adc_dat = REG_READ(ADCx->DAT2);
adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN0, ADC0_CHN0_PDS2);
break;
case ADC_DAT_3:
adc_dat = REG_READ(ADCx->DAT3);
adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN0, ADC0_CHN0_PDS3);
break;
case ADC_DAT_4:
adc_dat = REG_READ(ADCx->DAT4);
adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN1, ADC0_CHN1_PDS4);
break;
case ADC_DAT_5:
adc_dat = REG_READ(ADCx->DAT5);
adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN1, ADC0_CHN1_PDS5);
break;
case ADC_DAT_6:
adc_dat = REG_READ(ADCx->DAT6);
adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN1, ADC0_CHN1_PDS6);
break;
case ADC_DAT_7:
adc_dat = REG_READ(ADCx->DAT7);
adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN1, ADC0_CHN1_PDS7);
break;
case ADC_DAT_8:
adc_dat = REG_READ(ADCx->DAT8);
adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN2, ADC0_CHN2_PDS8);
break;
case ADC_DAT_9:
adc_dat = REG_READ(ADCx->DAT9);
adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN2, ADC0_CHN2_PDS9);
break;
case ADC_DAT_10:
adc_dat = REG_READ(ADCx->DAT10);
adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN2, ADC0_CHN2_PDS10);
break;
case ADC_DAT_11:
adc_dat = REG_READ(ADCx->DAT11);
adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN2, ADC0_CHN2_PDS11);
break;
default:
adc_dat = 0;
break;
}
// 先按照int16处理一下
adc_dat = (int16_t)(adc_dat & 0xffff);
// ADC0/1采样公共通道4/5/6/7时,负端电压为2.4V,实际允许的输入电压范围是
// if ((adc_chn == 4) || (adc_chn == 5) || (adc_chn == 6) || (adc_chn == 7))
// {
// int32_t dat = adc_dat;
// if (REG_READ_BIT(SYS_AFE_REG4, BIT4) == 0)
// {
// if (REG_READ_BIT(ADC0_CFG, ADC0_CFG_DATA_ALIGN_BIT) == 0)
// { // 左对齐
// dat = dat + 0x5550;
// adc_dat = dat;
// }
// else
// { // 右对齐
// dat = dat + 0x555;
// adc_dat = dat;
// }
// }
// }
return adc_dat;
}
/**
* @brief 获取当前温度
* @param ADC_value ADC采样值
* @return 当前温度值,单位为摄氏度
*/
s16 TMP_GetCurrentTemperature(s16 ADC_value)
{
s16 t_Temperture;
if (ADC1->CFG & BIT10)
{
t_Temperture = (tmp_b - ((s32)tmp_k * ADC_value) / 1000);
}
else
{
t_Temperture = (tmp_b - ((s32)tmp_k * (ADC_value >> 4)) / 1000);
}
return t_Temperture;
}
/**
* @brief 设置第每次的采样通道,例如ADC_SetChn(ADC0,ADC_DAT_0,ADC_CHN_0),把adc第一次采样的通道设置为通道0
* @param ADCx: ADC模块指针,指向ADC0或ADC1
* @param datx: 数据寄存器序号,如ADC_DAT_0
* @param chnx: ADC采样通道序号枚举定义,如ADC_CHN_0
*/
void ADC_SetChn(ADC_TypeDef *ADCx, ADC_DAT_x datx, ADC_CHN_x chnx)
{
uint8_t n = (datx & 0x3) * 4;
switch (datx)
{
case ADC_DAT_0:
REG_WRITE(ADCx->CHN0, (REG_READ(ADCx->CHN0) & (~(0xf << n))) | (chnx << n));
break;
case ADC_DAT_1:
REG_WRITE(ADCx->CHN0, (REG_READ(ADCx->CHN0) & (~(0xf << n))) | (chnx << n));
break;
case ADC_DAT_2:
REG_WRITE(ADCx->CHN0, (REG_READ(ADCx->CHN0) & (~(0xf << n))) | (chnx << n));
break;
case ADC_DAT_3:
REG_WRITE(ADCx->CHN0, (REG_READ(ADCx->CHN0) & (~(0xf << n))) | (chnx << n));
break;
case ADC_DAT_4:
REG_WRITE(ADCx->CHN1, (REG_READ(ADCx->CHN1) & (~(0xf << n))) | (chnx << n));
break;
case ADC_DAT_5:
REG_WRITE(ADCx->CHN1, (REG_READ(ADCx->CHN1) & (~(0xf << n))) | (chnx << n));
break;
case ADC_DAT_6:
REG_WRITE(ADCx->CHN1, (REG_READ(ADCx->CHN1) & (~(0xf << n))) | (chnx << n));
break;
case ADC_DAT_7:
REG_WRITE(ADCx->CHN1, (REG_READ(ADCx->CHN1) & (~(0xf << n))) | (chnx << n));
break;
case ADC_DAT_8:
REG_WRITE(ADCx->CHN2, (REG_READ(ADCx->CHN2) & (~(0xf << n))) | (chnx << n));
break;
case ADC_DAT_9:
REG_WRITE(ADCx->CHN2, (REG_READ(ADCx->CHN2) & (~(0xf << n))) | (chnx << n));
break;
case ADC_DAT_10:
REG_WRITE(ADCx->CHN2, (REG_READ(ADCx->CHN2) & (~(0xf << n))) | (chnx << n));
break;
case ADC_DAT_11:
REG_WRITE(ADCx->CHN2, (REG_READ(ADCx->CHN2) & (~(0xf << n))) | (chnx << n));
break;
}
}