打印
[PIC32/SAM]

Cortex®-M0+的32位单片机SAMD21,内部温度传感器监测环境温度,用MCC配置省时省力

[复制链接]
778|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Libby@|  楼主 | 2024-5-27 15:20 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 Libby@ 于 2024-6-5 11:28 编辑

#技术资源#
32位单片机SAMD21,采用内部温度传感器监测环境温度,通过MCC配置省时省力

       SAMD21单片机内置了温度传感器,可以用来监测环境温度。通过配置Timer定时采样,并利用事件系统触发ADC转换,避免占用MCU资源。温度数据通过轮询的方式读取,每次ADC有新数据时,读取12位数据并转换为温度值。需要注意的是,每个芯片都有自己的温度校准值,存储在NVM User Row中,需提前读取这些校准值代入计算公式。SAM D21 Curiosity Nano评估板(32 位 SAM 系列微控制器 SAMD21G17D)为例,借助事件系统和Timer,触发ADC转换,通过Microchip Code ConfiguratorMCC)进行快速配置,以最大限度地减少代码编写的工作量。

新建工程,进入MCC配置界面,添加组件 ADC/TC3/SERCOM5/EVSYS(新建项目,可参考我之前的贴子)

(1) 添加ADC模块,设置ADC为单端模式,并配置温度传感器为输入通道,参考电压选择1.0V, 采用硬件触发转换。

(2) 配置Timer,选择合适的定时周期,当溢出时,触发ADC转换



(3) 设置EVSYS,将 Timer 的溢出事件连接到 ADC 。TC3溢出产生事件,ADC为使用者,当设置正确,Event Status和User Ready显示绿色


(4) 配置 USART 进行调试打印,SAM D21 Curiosity Nano板子,SERCOM5作为串口输出,设置波特率及TX和RX。MCC自带工具STDIO,直连到SERCOM5。



(5) 单击“Generate”按钮,MCC可以生成相应的初始化代码,回到Projects可查看初始化的代码。

(6) 添加代码,可查看芯片手册Temperature Sensor的公式,根据得到的ADC值计算得到摄氏度。在代码中添加读取NVM User Row中温度校准值的函数。在主循环中添加轮询代码,当ADC转换完成时,读取数据并根据校准值进行温度计算。




以下是main.c的片段:温度参数及公式可参见数据手册--温度传感器特性,由于参数过多,未贴出。有小伙伴需要完整的计算过程,如下


#define INT1V_VALUE_FLOAT                    1.0
#define INT1V_DIVIDER_1000                    1000.0
#define ADC_12BIT_FULL_SCALE_VALUE_FLOAT    4095.0

float input_voltage;
static uint16_t Adc_value;
float coarse_temp; /* Coarse value of the temperature - tempC */
float fine_temp; /* Finer value of the temperature - tempF */

float tempR; /* Production Room Temperature value read from NVM memory - tempR */
float tempH; /* Production Hot Temperature value read from NVM memory - tempH */
float INT1VR; /* Room temp 2's complement of the internal 1V reference value - INT1VR */
float INT1VH; /* Hot temp 2's complement of the internal 1V reference value - INT1VR */
float VADCR; /* Room Temperature ADC voltage - VADCR */
float VADCH; /* Hot Temperature ADC voltage - VADCH */

uint16_t ADCR; /* Production Room Temperature ADC Value read from NVM memory - ADCR */
uint16_t ADCH; /* Production Hot Temperature ADC Value read from NVM memory - ADCH */

/* This function helps to convert the Decimal value into fractional value
   for decimal values from Temperature Log Row Content */

float convert_dec_to_frac(uint8_t val) {
    if (val < 10) {
        return ((float) val / 10.0);
    } else if (val < 100) {
        return ((float) val / 100.0);
    } else {
        return ((float) val / 1000.0);
    }
}

/* This function helps us to read and store the production calibration data to variables for temperature calculation */

void load_temperature_log_row_data(void) {
    volatile uint32_t val1; /* Temperature Log Row Content first 32 bits */
    volatile uint32_t val2; /* Temperature Log Row Content another 32 bits */
    uint8_t room_temp_val_int; /* Integer part of room temperature in °C */
    uint8_t room_temp_val_dec; /* Decimal part of room temperature in °C */
    uint8_t hot_temp_val_int; /* Integer part of hot temperature in °C */
    uint8_t hot_temp_val_dec; /* Decimal part of hot temperature in °C */
    int8_t room_int1v_val; /* internal 1V reference drift at room temperature */
    int8_t hot_int1v_val; /* internal 1V reference drift at hot temperature*/
    uint32_t *temp_log_row_ptr = (uint32_t *) TEMP_LOG_ADDR;

    val1 = *temp_log_row_ptr;
    temp_log_row_ptr++;
    val2 = *temp_log_row_ptr;

    room_temp_val_int = (uint8_t) ((val1 & FUSES_TEMP_LOG_WORD_0_ROOM_TEMP_VAL_INT_Msk) >> FUSES_TEMP_LOG_WORD_0_ROOM_TEMP_VAL_INT_Pos);

    room_temp_val_dec = (uint8_t) ((val1 & FUSES_TEMP_LOG_WORD_0_ROOM_TEMP_VAL_DEC_Msk) >> FUSES_TEMP_LOG_WORD_0_ROOM_TEMP_VAL_DEC_Pos);

    hot_temp_val_int = (uint8_t) ((val1 & FUSES_TEMP_LOG_WORD_0_HOT_TEMP_VAL_INT_Msk) >> FUSES_TEMP_LOG_WORD_0_HOT_TEMP_VAL_INT_Pos);

    hot_temp_val_dec = (uint8_t) ((val1 & FUSES_TEMP_LOG_WORD_0_HOT_TEMP_VAL_DEC_Msk) >> FUSES_TEMP_LOG_WORD_0_HOT_TEMP_VAL_DEC_Pos);

    room_int1v_val = (int8_t) ((val1 & FUSES_TEMP_LOG_WORD_0_ROOM_INT1V_VAL_Msk) >> FUSES_TEMP_LOG_WORD_0_ROOM_INT1V_VAL_Pos);

    hot_int1v_val = (int8_t) ((val2 & FUSES_TEMP_LOG_WORD_1_HOT_INT1V_VAL_Msk) >> FUSES_TEMP_LOG_WORD_1_HOT_INT1V_VAL_Pos);

    ADCR = (uint16_t) ((val2 & FUSES_TEMP_LOG_WORD_1_ROOM_ADC_VAL_Msk) >> FUSES_TEMP_LOG_WORD_1_ROOM_ADC_VAL_Pos);

    ADCH = (uint16_t) ((val2 & FUSES_TEMP_LOG_WORD_1_HOT_ADC_VAL_Msk) >> FUSES_TEMP_LOG_WORD_1_HOT_ADC_VAL_Pos);

    tempR = room_temp_val_int + convert_dec_to_frac(room_temp_val_dec);

    tempH = hot_temp_val_int + convert_dec_to_frac(hot_temp_val_dec);

    INT1VR = 1 - ((float) room_int1v_val / INT1V_DIVIDER_1000);

    INT1VH = 1 - ((float) hot_int1v_val / INT1V_DIVIDER_1000);

    VADCR = ((float) ADCR * INT1VR) / ADC_12BIT_FULL_SCALE_VALUE_FLOAT;

    VADCH = ((float) ADCH * INT1VH) / ADC_12BIT_FULL_SCALE_VALUE_FLOAT;

}

/* This function return the Fine temperature value after done with calculation using Equation1 and Equation 1b as mentioned in data sheet on 37.11.8 Temperature Sensor Characteristics */


float calculate_temperature(uint16_t raw_code) {

    float VADC; /* Voltage calculation using ADC result for Coarse Temp calculation */
    float VADCM; /* Voltage calculation using ADC result for Fine Temp calculation. */
    float INT1VM; /* Voltage calculation for reality INT1V value during the ADC conversion */

    VADC = ((float) raw_code * INT1V_VALUE_FLOAT) / ADC_12BIT_FULL_SCALE_VALUE_FLOAT;

    /* Coarse Temp Calculation by assume INT1V=1V for this ADC conversion */
    coarse_temp = tempR + (((tempH - tempR) / (VADCH - VADCR)) * (VADC - VADCR));

    /* Calculation to find the real INT1V value during the ADC conversion */
    INT1VM = INT1VR + (((INT1VH - INT1VR) * (coarse_temp - tempR)) / (tempH - tempR));

    VADCM = ((float) raw_code * INT1VM) / ADC_12BIT_FULL_SCALE_VALUE_FLOAT;

    /* Fine Temp Calculation by replace INT1V=1V by INT1V = INT1Vm for ADC conversion */
    fine_temp = tempR + (((tempH - tempR) / (VADCH - VADCR)) * (VADCM - VADCR));

    return fine_temp;

}


int main(void) {
    float temperature;
    /* Initialize all modules */
    SYS_Initialize(NULL); //初始化
    load_temperature_log_row_data();  // 读取校准值
    printf("\r\n *********************************************** \r\n");
    printf("\r\n          Temperature \r\n");
    printf("\r\n *********************************************** \r\n");
    ADC_Enable(); //使能ADC
    TC3_TimerStart();// 启动TC3

    while (true) {

        if (ADC_ConversionStatusGet() == 1) {
            Adc_value = ADC_ConversionResultGet();     // 读取 ADC 结果
            input_voltage = Adc_value / ADC_12BIT_FULL_SCALE_VALUE_FLOAT; //转化成电压值
            temperature = calculate_temperature(Adc_value);  // 温度转换(根据数据手册和校准值)
            printf("\r\n:ADC Voltage : %4d, Voltage :%2.3fV, Temperature in room:%2.1fC\r\n\r\n", Adc_value, input_voltage, temperature);
        }
   
    }

    /* Execution should not come here during normal operation */

    return ( EXIT_FAILURE);
}


/*******************************************************************************
End of File
*/

通过上述步骤,快速配置 SAMD21 的内部温度传感器、定时器和事件系统,从而减少代码工作量,以最小化占用 MCU ,监测环境温度。

欢迎大家留言讨论

使用特权

评论回复
沙发
原来是wjc| | 2024-9-28 22:56 | 只看该作者
充分体验3 nm工艺技术提供高性能和低功耗性能。

使用特权

评论回复
板凳
原来是wjc| | 2024-9-28 23:18 | 只看该作者
充分体验3 nm工艺技术提供高性能和低功耗性能。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

8

主题

51

帖子

0

粉丝