第五课 AD转换
本节课开始学习RL78/G13的AD转化功能,先实现单通道转化。
一、Code Generator设置
1、AD Conveter设置
打开设置,发现一大堆需要勾选的选项,不着急,咱们一个一个来看来解决。
五个五个地讲解吧。
1.1 第一组
1.1.1 A/D converter operation setting
Unused / Used
决定整个 ADC 模块要不要被初始化代码包含。选 Unused 时,下面所有设置都被忽略,ADC 时钟也不会打开。
1.1.2 Comparator operation setting
Stop / Operation
RL78/G13 内部带一个模拟比较器,和 ADC 共用部分引脚。
Stop → 比较器断电;Operation → 比较器使能。
如果没用比较器,务必选 Stop,可省几百 µA 电流。
这里需要勾选,否则AD比较器不运行。
1.1.3 Resolution setting
10 bits → 真正 10 位 SAR 结果,ADCR 范围 0-1023。
8 bits → 只取高 8 位,ADCR 范围 0-255,转换时间略短,噪声分辨率降低。
1.1.4 VREF(+) setting 正参考源三选一
VDD:直接拿电源当参考,省事但精度受电源纹波影响。
AVREFP:把参考引到外部 AVREFP 引脚,可接精密基准。
Internal reference voltage:片内 1.45 V 典型基准,只能测 ≤1.45 V 的信号,温漂 ~±30 ppm/°C。
1.1.5 VREF(-) setting
负参考源二选一
VSS:芯片地。
AVREFM:外部引脚,可接偏置电压,实现“单极性输入、差分测量”。
1.2 第二组
1.2.1Trigger mode setting
Software trigger mode:代码里写 ADCS = 1 才启动一次转换。
Hardware trigger no wait mode:检测到硬件触发(INTTM01 或其它)立即开始,不等待当前序列结束。
Hardware trigger wait mode:若上次序列未完成,先等它结束再启动新序列,避免冲突。
1.2.2 Operation mode setting(扫描方式)
Continuous select mode:只采 一个通道,连续不断地自动重复。
Continuous scan mode:把 选中的一组通道 顺序扫完,再从头循环。
One-shot select mode:只采 一个通道,采完一次就停,需重新触发。
One-shot scan mode:把 选中的一组通道 顺序扫完一次就停。
区别就是“单通道/多通道”与“单次/连续”的排列组合。
ANI0-ANI7 analog input selection
勾选哪个引脚,就把它加入扫描列表;同时 CS+ 会自动把对应引脚配置成“模拟输入”,禁止数字输出驱动。
ANI16-ANI19 analog input selection
同上,只是通道号在 16-19,对应封装上的 ANI16…ANI19 引脚。
A/D channel selection(下拉框)
只在“单通道”类模式(Continuous/One-shot select)出现,指定到底采刚才勾选的列表中的哪一个。
1.2.3 Conversion time mode
Normal1 / Normal2 / LowPower … 等几种预设计数组合,区别是采样保持窗口长度。
选 Normal1 时,采样脉冲 = 9.5 个 ADC 时钟,换算后 304/fCLK。
源阻抗高或信号建立慢时,可把 mode 改成更长采样窗口的 Normal2/3。
Conversion time(只读提示)
根据上面 mode 和当前 fCLK 自动算出,告诉你一次转换大概需要多少 µs。
例:fCLK=32 MHz → 304/32 M ≈ 9.5 µs。
1.2.4 Generates an interrupt request …
打勾后,ADC 会在“结果落在上下限区间外”时产生 INTAD,而不是每次转换完都中断。
用来做“窗口比较器”式报警,例如电池电压高/低限监测。
Upper-bound (ADUL) / Lower-bound (ADLL)
填写 8 位边界值(0-255)。
注意:即使 ADC 工作在 10 位模式,这里也只取结果寄存器 ADCRH(高 8 位) 做比较,因此要把 10 位阈值右移 2 位后填进来。
例:想设 3.0 V 上限,VREF=5 V → 3.0/5×1023≈614 → 614>>2=153 → ADUL=153。
1.2.5 Use A/D interrupt (INTAD) / Priority
打勾才允许 ADC 中断,优先级可选 High/Upper/Middle/Low。
若用“窗口比较”功能,也必须把这里打开,否则不会产生中断向量。
二、生成代码与测试
1、编写代码
自动生成代码后,左边多出了关于AD的.c文件。
1.1 r_cg_adc.c
r_cg_adc.h中列出了这些新增的函数,其中,R_ADC_Create()在硬件里面自动添加运行了,R_ADC_Set_OperationOn()咱们在Code Generator的AD Conver,第二个选项里面初始化自动开启了,需要咱们手动操作的是:R_ADC_Start()和R_ADC_Get_Result()。
R_ADC_Create()需要注意ADS的赋值,这个寄存器负责选择AD转化通道,这里最前面的13其实是0x13,也就是十进制的19,对应了咱们开始选的19通道。
R_ADC_Start()这个函数和其他启动函数一样,放在main函数的R_MAIN_UserInit()函数里面;
R_ADC_Get_Result()需要重点看下。
这里是定义了一个常量指针buffer,指向一个16位变量。
buffer 是一个 “常量指针”(constant pointer)。
一旦给它赋了初值,以后再也不能把别的地址塞给 buffer;
但通过 *buffer = 0x1234; 去改它指向的 RAM 单元完全合法。
注意到,这里buffer指向的是6次右移位的ADCR的值,ADCR就是最后电压转化值。
右移6位意味着除以64,所以芯片手册里面,*buffer 的值就是ADCR/64。
1.2 r_cg_adc_user.c
里面有一个中断函数。由于开启了中断,ADC每次转化完成就进一次中断,所以需要定义一个变量,在中断里面用来存储buffer值,后面调试的时候方便读取。
2、 调试运行
编译并下载,F5全速运行,然后暂停,会发现已经有值了。
862就是ADCR/64的结果,(862-0.5)*5/1024=4.206V。
这里IN19的电阻值调到了最大,根据电路图,AD0的范围应该是0~5/6VCC,也就是0~4.167V,误差在合理范围之内。
下面是DeepSeek的分析
电路分析
VCC = 5V
R1 = 10kΩ 固定电阻
R3 = 0~50kΩ 可变电阻(电位器)
AD0 连接到R3的滑动端,C1 = 0.47μF 作为滤波电容(对直流分析无影响)。
AD0处的电压由R1和R3组成的分压电路决定:
当R3的滑动端移动到最底部(接近AGND)时,AD0电压为0V。
当R3的滑动端移动到最顶部(接近R1与R3的连接点)时,AD0电压达到最大值。此时,电路相当于R1和R3串联,最大电压为:
Vmax=VCC×R3R1+R3=5×5010+50=5×5060=256≈4.1667VVmax=VCC×R1+R3R3=5×10+5050=5×6050=625≈4.1667V
因此,AD0处的电压变化范围是 0V 至 4.1667V。
ADC读数分析
RL78/G13的ADC是10位分辨率,输出范围是0到1023(即1024个等级),参考电压通常为VCC(5V)。因此,ADC输出值(记为AD_value)与输入电压(V_AD0)的关系为:
AD_value=V_AD0VCC×1024AD_value=VCCV_AD0×1024
当 V_AD0 = 0V 时,AD_value = 0。
当 V_AD0 = 4.1667V 时,预期ADC值为:
AD_value=4.16675×1024≈0.83334×1024≈853.3AD_value=54.1667×1024≈0.83334×1024≈853.3
理论上,ADC值应接近853。
您实测的ADC值从0到862变化,其中862对应最大电压。计算862对应的电压:
V_AD0=8621024×5≈0.8418×5≈4.209VV_AD0=1024862×5≈0.8418×5≈4.209V
这与理论值4.1667V相比,略高约0.042V,相对误差约为1%。
为什么ADC读数为862?
电阻公差:R1和R3的实际值可能偏离标称值(10kΩ和50kΩ)。例如,如果R1略小于10kΩ或R3略大于50kΩ,会导致分压电压稍高。
参考电压误差:VCC可能不是精确的5V(如电源波动或负载影响),导致ADC参考电压变化。
ADC本身误差:RL78/G13的ADC有固有的增益误差和偏移误差,通常误差范围在±1%到±2%之间,属于正常范围。
计算近似:您提到862/1024 ≈ 5/6,但5/6 ≈ 0.8333,而862/1024 ≈ 0.8418,两者略有差异。理论计算值853/1024 ≈ 0.8330,与5/6更接近。实测862可能由于上述误差因素导致。
结论
您的ADC读数从0到862变化是合理的,与理论范围0到853相比,误差在典型范围内(约1%)。在实际应用中,这种误差通常可接受,可以通过软件校准或使用更精确的元件来改善。如果您需要更精确的读数,建议检查电源稳定性和电阻实际值,并在代码中实施校准步骤。
如果您有更多细节(如实际电阻值或参考电压测量),可以进一步分析。
三、AD多通道
多通道需要在Operation mode setting里面进行选择。
1、Continuous select mode与Continuous scan mode
这两种模式,中文名分别是连续选择模式和连续扫描模式,在连续选择模式下,AD仅重复读取指定通道的置;在连续扫描模式下,AD会按顺序读取指定的4个通道,每读完一个通道就将值保存在ADCR寄存器中,然后进一次中断,如果不取出这个值,那么下次进中断前就会被新值替换掉。
这里的input selection只是选择将哪些通道设置为非GPIO口,如果不选,这些口就是普通的GPIO口。
选择了Continuous scan mode 后,然后input selection 选择多个通道,下面的A/D channel selection就可以选其中的4个通道进行连续扫描模式了。
2、采集18、19通道数据
这里不采集过多数据了,只采集18、19通道数据,其他口都默认是普通数字口,A/D channel selection 选择ANI18,也就是默认转化18通道的输入信号,如果想转化19的,就需要手动设置ADS的值。
转化时间选默认的,而且如果对时间要求不严格,将转化时间尽量选大一些,否则会出现转化不完全的现象。比如我有次不小心将转化时间选的过小,导致Debug时,F5全速运行,转化出来的值中间有好个是0、转化次序错乱的现象。
接下来在中断函数中写转存数值和通道转化的代码:
跟之前讲过的一样,令ADS是几,就会转化第几通道的输入值,然后我发现了一个问题,就是我虽然没打开18、19以外的其他通道,但是这里我直接令ADS=其他通道,依然能读出其他通道的输入信号值。这点在下一节讲一讲。
3、遇到的问题
3.1 ADS滥用
如果我在Operating mode setting 的设置里面,ANI0-ANI7 analog input selection下拉框中选择了All digital,后面我令ADS = 2,也能读取ANI2端口的值,与我在下拉框中选择ANI0-ANI2,然后再令ADS = 2,读取值有什么不同?
一句话先说结论:
下拉框选“All digital” → CS+ 不会把 ANI2 引脚配置成模拟输入,PxOD、PMC 仍保持数字口;
后面你手动写 ADS = 2 → ADC 硬件照样能采,但引脚还在推挽/上拉/下拉数字模式,读数精度变差,甚至烧毁 IO;
下拉框先勾 ANI0-ANI2 → CS+ 自动把对应脚设为模拟输入(关输出驱动、关上下拉),精度最高,也是官方推荐做法。
下面把寄存器级差异列给你:
步骤All digital → 手动 ADS=2先勾 ANI0-ANI2 → 再 ADS=2PMC2 位0(数字功能)1(模拟功能)POM2 位0/1 按旧配置0(取消开漏)PU2/PD2可能仍上拉/下拉上下拉关闭P2OD 位0/1 可能推挽输出0(输出驱动关闭)ADC 采样能采,但内部 12 pF 电容与数字驱动打架 → 建立慢、误差大纯高阻模拟口,建立时间合规风险若程序把 P2.2 配成输出,5 V 对推挽口 = 烧毁无风险,硬件已禁止数字功能
因此:
实验/验证可以靠“All digital + 手动 ADS”偷懒;
正式产品一定要让下拉框勾选对应通道,让工具把引脚配成模拟,再开始 ADC。
3.2 电压不正确
在上次AD单通道的测试中,能读出下面的值,并计算出AD0的范围应该是0~5/6VCC。
后面我买了一个万用表,想验证下电压值是否正确。
结果出人意料,量出ANI19的电压值是2.75V,思考了半天也没想明白,后来不经意间看到了EZ-CUBE2,才想起来挡位一直用的是3.3V供电输出给开发板,然后我接着用万用表测量了VCC的电压,果然是3.3V,而2.75V = 5/6VCC=3.3V。和我上面的推算是一样的。
然后我将EZ-CUBE2输出电压改为5V,继续测量ANI19的值,结果还是不对!是3.8V!
我继续测量VCC,发现只有4.6V。。。
完全正常,4.6 V 左右是 EZ-CUBE2 的“5 V”口在轻载下的真实输出,原因有三:
USB 供电源头只有 5 V±5 %
EZ-CUBE2 本身由 USB 口取电,大多数 PC 的 USB-A 口空载电压 4.95 V 左右,再经过板内电缆、保险丝、MOSFET 开关、线损,到插头只剩 4.7 V 量级。
板载 LDO 的压降
调试器内部还要通过一颗 100 mA 级小 LDO 给目标板供电,LDO 本身有 0.1–0.2 V 压降(负载越大压降越明显),于是 4.7 V 再掉 0.1 V 就变成 4.6 V。
测量点又在目标板远端
你测的是 RL78 开发板的 VDD 焊盘,还要经过 20 cm 排线 + 0 Ω 电阻 + 电源平面铜箔,又吃掉几十毫伏,最终看到 4.62 V 完全符合预期。
实测参考
网上多篇调试笔记都给出 EZ-CUBE2 “5 V”口空载 ≈ 4.6–4.7 V 的数据;
只要 > 4.5 V,RL78 的 “High-speed main 2.7–5.5 V” 模式就完全满足,不影响下载、不影响全速运行。
为了省接线,我用EZ-CUBE2给开发板供电,导致供电只有4.6V,然后我用USB直接给开发板供电,再继续调试,终于,终于测出来电压是4.2V了。