九、A-D转换器获取温度

9.1 ADC简介

AD转换器(Analog-to-Digital Converter,模数转换器)是一种将连续的模拟信号(如电压、电流)转换为离散的数字信号(二进制代码)的电子器件。它是连接现实模拟世界与数字系统的桥梁,广泛应用于数据采集、传感器信号处理、通信系统等领域。

LPC1100系列中有10位逐次逼近式ADC,在8个引脚中实现输入多路复用。逐次逼近式在算法上就叫做二分,通过十次二分,求得引脚上的电压值。通过读到的十位数字,线性映射到电压上即可。具体如下图

因为每次二分都会比较出来一位,具体如下

  • 第一次二分:将输入电压与中间值(Vref/2Vref​/2)比较,确定输入电压是在上半部分还是下半部分。

  • 第二次二分:根据第一次的结果,将范围缩小到 Vref/4Vref​/4 或 3Vref/43Vref​/4,再次比较。

  • 重复:每次比较都将范围缩小一半,直到完成 10 次二分搜索,最终确定输入电压的精确值。

得到十位结果之后,除以2^10 - 1 再乘以 3.3v就是最终得到的电压

实际使用时,以上内部二分原理用不到(≈白学了,实则不然,更清晰了),我们只需要启动ADC,等待转换完成,从数据寄存器读取结果然后套个公式就行了。

        一句话,ADC就是模拟转数字求引脚电压的。

9.2 被采样器件 KNTC0603/10KF3950 简介

9.2.1 基本特性

        KNTC0603/10KF3950 是一种 负温度系数热敏电阻(NTC Thermistor) 的型号。

        NTC(Negative Temperature Coefficient)热敏电阻,即电阻值随温度升高而减小

  • 封装:0603(表示尺寸为 0.06 英寸 × 0.03 英寸,即 1.6mm × 0.8mm)。

  • 标称电阻值:10kΩ(在 25°C 时的电阻值)。

  • B 值:3950K(B 值是描述热敏电阻温度特性的参数,B 值越大,温度变化对电阻值的影响越明显)。

9.2.2 主要参数

9.2.3 工作原理

       先看电路图

R / (R + 10k)*V = ADCvalue / 2^10 * V

R = 10k * ADC / (2^10  - ADC)

          原理就是ADC转换得到PIO1_11处的电压值,然后根据分压得到该热敏电阻的阻值,阻值与温度之间有一种神秘的关系,然而数据手册不语,打了几张RT表。。。

KNTC0603/10KF3950 -PDF数据手册-参考资料-立创商城

9.3 寄存器

9.3.1 控制寄存器 AD0CR

符号描述
7:0SEL

选择采样和转换的输入脚

第16位的BURST控制了两种模式

BURST = 0 软件控制模式下,只能有一个位被置1,也就是只能有一个通道开

BURST = 1 硬件控制模式下,可选用任意数目的通道

       另外,把全部为0当作为0x01,即通道0开

15:8CLKDIVAPB时钟(PCLK)进行分频(/(CLKDIV + 1)),得到AD转换时钟,考虑到各方面原因,该时钟必须小于等于 4.5 MHz ,而且通常情况要求CLKDIV尽量小(ADCLK 越高,AD 转换的速度越快,可快速采样,提高效率和性能),这时就应该选择合适的值使得AD时钟接近甚至等于4.5MHz
16BURST

0 软件控制模式,转换由软件控制,11个时钟完成一次

1 硬件控制模式,以[19:17]位CLKS选择的速率 从低位到高位扫描,对[7:0]位SEL中置一的进行转换

BURST置1则[26:24]START必须为0

19:17CLKS

硬件扫描模式下每次转换占用的时钟数以及AD0DRn中转换结果的有效位数,最高十次二分对吧

000 11个时钟/10位

001 10个时钟/9位

010 9个时钟/8位

011 8个时钟/7位

100 7个时钟/6位

101 6个时钟/5位

110 5个时钟/4位

111 4个时钟/3位

23:20保留
26:24START

BURST = 0软件控制模式下,第27位EDGE指定的边沿下,选中的位何时启动

000 不启动

001 立即启动转换

010  边沿出现在PIO0_2/SSEL/CT16B0_CAP0时启动

011  边沿出现在PIO1_5/DIR/CT32B0_CAP0时启动

100  边沿出现在CT32B0_MAT0时启动

101  边沿出现在CT32B0_MAT1时启动

110  边沿出现在CT16B0_MAT0时启动

111  边沿出现在CT16B0_MAT1时启动

27EDGE

只有在[26:24]START 在 010~111时有效

0 所选信号的上升沿

1 所选信号的下降沿

31:28保留

9.3.2 全局数据寄存器 AD0GDR

        包含最近一次A-D转换的结果

符号描述
5:0未使用(10次二分,最多十位)
15:6V/VREF二分得到的值也就是真实电压与最大电压的比
23:16多的连续的A-D值从[15:6]溢出到这里,防止影响高位
26:24CHNLS位转换通道
29:27未使用,未来CHN扩展
30OVERRUN

提示系统可能存在数据处理不及时或数据丢失的问题

BURST模式下,LS位结果的转换有一个或多个转换结果丢失或被覆盖,该位会置一

31DONE

A-D转换结束该位会置一

读该寄存器和写ADCR都会清零该位

转换过程中读ADCR会置位该位并启动新转换

9.3.3 状态寄存器 AD0STAT

符号描述
7:0DONE[7:0]反映每个A-D通道的结果寄存器中DONE的状态
15:8OVERRUN[7:0]反映每个A-D通道的结果寄存器中OVERRUN的状态, 允许同时检查所有A-D状态
16ADINTA-D中断标志。任何一条A-D通道的DONE置一且使能A-D产生中断时,该位置一
31:17保留

9.3.4 中断使能寄存器 AD0INTEN

符号描述
7:0AD0INTEN[7:0]哪一位置一,哪一位转换结束就会产生中断
8ADGINTEN

0 相当于无效 

1 [7:0]位当无效处理,任意通道A-D转换结束都产生中断,即全部使能

31:9未使用,全0

9.3.5 数据寄存器 AD0DR0~AD0DR7

        保存各个通道的转换结果及一些标志

描述
5:0未用,二分次数不够
15:6V/VREF采样到的数据
29:16未用,低位溢出的到这
30OVERRUNBURST模式下数据处理不及时或数据丢失置一
31DONEA-D转换完成时该位置一,在读寄存器时清零

9.4 读取温度

        此处使用了32位定时器以2Hz发送信号,每次在中断里手动转换

         有个小问题就是,不知道边沿转换怎么实现的

main.c

#include <LPC11xx.h>
#include "LED.h"
#include "Button.h"
#include "TIMER.h"
#include "UART.h"
#include "string.h"
#include "ADC.h"
int main(void)
{
	LED_Init();
    LED_ON();
    UART_Init();
    
    char message[] = "Hello, ADC!";// 定义要发送的数据
    int length = strlen(message); // 计算数据长度,不包括结束符 '\0'
    UART_Send(message, length);	// 调用UART_Send函数发送数据
	
	ADC_init();
	TMR32B0_Init();
	
    while (1)
    {
		
    }
}

ADC.c

#include "ADC.h"
#include "UART.h"
uint32_t ADC7Value = 0; // 采样值
void ADC_init(void)
{
	LPC_SYSCON -> SYSAHBCLKCTRL |= (1UL << 6) | (1UL << 16); //使能GPIO和IO配置时钟
	
	LPC_IOCON -> PIO1_11 &= ~0x9f; // 把P1.11引脚选择模拟输入方式
	LPC_IOCON -> PIO1_11 |= 0x01; // 将PIO1_11 配置为AD7

	LPC_SYSCON -> PDRUNCFG &= ~(1UL << 4);  // 打开电源
	LPC_SYSCON -> SYSAHBCLKCTRL |= (1UL << 13);// 使能ADC时钟 
	
	LPC_ADC -> CR = (1UL << 7) |       	//选择AD7引脚 
					(23UL << 8)|		//ADC时钟24MHz/24 	
					(0UL << 16)|		//BURST = 0,软件控制模式		
					(0UL << 17)|		//11个时钟/10位
					(0UL << 24)| 		// 不启动
					(0UL << 27);		//MAT信号上升沿启动转换
	LPC_ADC->INTEN =  (1UL << 7); //AD7使能中断
	NVIC_EnableIRQ(ADC_IRQn); //使能ADC中断
}

#include <math.h>
#include <stdio.h>
#include <string.h>
// 网上找的求温度的代码
float resistance2Temperature(float R1) 
{
  float B = 3950.0f;
  float R2 = 10000.0f;
  float T2 = 25.0f;
  return (1.0 / ((1.0 / B) * log(R1 / R2) + (1.0 / (T2 + 273.15))) - 273.15);
}

void ADC_IRQHandler()
{
	uint32_t regVal;
	regVal = LPC_ADC -> STAT; // 读状态寄存器
	if((regVal & 0xFF) & (0x01 << 7)) // 如果通道7 A-D转换完成
	{
		ADC7Value = (LPC_ADC -> DR[7] >> 6) & 0x3FF; //读取AD7的值,读完自动清除中断
		
		float R = ADC7Value / (1024.0f - ADC7Value) * 10000.0f;
		float T = resistance2Temperature(R);
		
		char buffer[20];
		int integerPart = (int)T; // 提取整数部分
		int decimalPart = (int)((T - integerPart) * 1000); // 提取小数部分(保留3位)
		sprintf(buffer, "%d.%03d", integerPart, decimalPart); // 格式化为字符串

		UART_Send(buffer, strlen(buffer));
	}

}


ADC.h

#ifndef _ADC_H_
#define _ADC_H_

#include <LPC11XX.h>
void ADC_init(void);


#endif

TIMER.c

#include "TIMER.h"
#include "UART.h"

void TMR32B0_Init(void)//32位定时器0初始化  设置中断时间 MR0/SystemCoreClock *(PR + 1) = 0.01s
{
	LPC_SYSCON->SYSAHBCLKCTRL |= (1UL << 9);//使能32位定时器0的时钟
	LPC_TMR32B0->IR = 0x1F;//清除所有中断标志位
	LPC_TMR32B0->PR = 0;//设置分频系数
	LPC_TMR32B0->MCR = 3;//设置MR0匹配后复位TC并产生中断
	LPC_TMR32B0->MR0 = SystemCoreClock / 2 ; // 计数值 频率2Hz
	LPC_TMR32B0->TCR = 0x01;//启动定时器
	NVIC_EnableIRQ(TIMER_32_0_IRQn);//开中断
}

void TIMER32_0_IRQHandler(void)//32位定时器0中断子程序
{
	if(LPC_TMR32B0->IR & 0x01)//判断是否MR0中断
	{
		LPC_TMR32B0->IR = 0x01; // 清除第一中断标志位
		// 单次启动ADC
		LPC_ADC -> CR |= 1UL << 24;
	}

}


void TMR16B1_Init(void)
{
    LPC_SYSCON->SYSAHBCLKCTRL |= (1UL << 8) | (1UL << 16); // 16位定时器1时钟使能 | IO配置块时钟使能
    LPC_IOCON->PIO1_9 |= 0x01; // MAT0匹配IO1_9    
}

void TMR16B1_PWM_Mode(void)// PWM呼吸灯模式 1s 占空比0 -> 1 or 1 -> 0
{
    LPC_TMR16B1->TCR = 0x02;//定时器复位
    LPC_TMR16B1->PR = 99; // 分频系数
    LPC_TMR16B1->PWMC = 0x01;//设置MAT0为PWM输出
    LPC_TMR16B1->MCR = 0x02 << 9; //设置MR3匹配后复位TC;
    LPC_TMR16B1->MR3 = SystemCoreClock / 10000; // PWM周期设置为0.01s,设置中断时间
    LPC_TMR16B1->MR0 = LPC_TMR16B1->MR3 / 100;//MAT0初始化输出亮度1%
    LPC_TMR16B1->TCR = 0x01; // 启动定时器
}

// 匹配输出翻转
void TMR16B1_Blinky_Mode(void) // 闪烁灯模式 1s翻转一次
{    
    LPC_TMR16B1->TCR = 0x02;//定时器复位
    LPC_TMR16B1->PR = 999; // 分频系数;
    LPC_TMR16B1->MCR = 2; // 设置MR0匹配后复位TC不产生中断;
    LPC_TMR16B1->MR0 = SystemCoreClock / 1; // 定时1s
    LPC_TMR16B1->PWMC = 0x00;//设置MAT0不为PWM输出
    LPC_TMR16B1->EMR |= (3UL << 4);// MAT0外部匹配翻转
    
    LPC_TMR16B1->TCR = 0x01; //定时器启动
}

TIMER.h

#ifndef _TIMER_H_
#define _TIMER_H_

#include <LPC11xx.h>

void TMR32B0_Init(void);
void TMR16B1_Init(void);
void TMR16B1_PWM_Mode(void);
void TMR16B1_Blinky_Mode(void);

#endif

效果图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值