本帖最后由 zxcscm 于 2012-2-15 22:56 编辑
我发现,学习某一个功能时,只是一味的看例程,将结果调试出来,总感觉并没有真正的掌握它
可能是因为还停留在51的学习习惯上,每学习一个功能总想弄清楚是具体怎么操作寄存器的,这样才觉得知根知底
所以又对着手册扒拉ADC的各个寄存器,这样做很笨也很费时间,也不知这种学习方法是否正确,但是心安
下面是对ADC初始化函数的一点分析
参考数据手册P449
三种操作模式: 单一(single), 单周期扫描(single-cycle scan) 和连续扫描模式(continuous scan). A/D 转换可由软件设定和外部STADCpin开启.
所有使能通道有三种操作模式
· 单一触发模式: A/D转换在指定通道完成一次
· 单周期扫描模式:A/D转换在指定通道完成一个周期,转换顺序从最小号通道到最大号通道
· 连续扫描模式: A/D持续执行单周期扫描模式直到软件停止A/D转换
每个通道有两种输入方式
·单端输入方式
·差分输入方式
A/D转换开始条件
· 软件向ADST 位写1
· 外部 pin STADC
首先配置ADC时钟
ADC有三个时钟源,可由两位ADC_S(CLKSEL[3:2])选择;
ADC 时钟频率按如下公式进行8位预分频: ADC时钟频率= (ADC clock source frequency) /(ADC_N+1)。
ADC_S在时钟源选择寄存器CLKSEL1[3:2]中设置【1】技术手册P162
ADC_N 在时钟分频寄存器CLKDIV[23:16]中设置. 【2】技术手册P167
通常来说,软件设置ADC_S与 ADC_N 获得 16 MHz 或稍低于16 MHz的频率。
接下对ADC的一系列寄存器进行配置,启动ADC即可, 详细过程见下面驱动程序:
一、DrvADC_Open(E_ADC_INPUT_MODEInputMode, E_ADC_OPERATION_MODE OpMode, uint8_t u8ChannelSelBitwise,E_ADC_CLK_SRC ClockSrc, uint8_t u8AdcDivisor)
感觉这个函数把ADC的所有寄存器都设置了一遍
原函数很长就不贴了
先来分析下几个形参,具体可见原函数的注释,这里只是稍微翻译了一下
1、 InputMode:指定模拟输入信号的类型,可选择
①.单端输入(single end input):
ADC_SINGLE_END
②.差分输入(differential input):
ADC_DIFFERENTIAL
2、OpMode:指定操作模式,可选择
①.
单一触发模式(single):ADC_SINGLE_OP
②.单周期扫描模式(singlecycle scan):ADC_SINGLE_CYCLE_OP
③.连续扫描模式(continuousscan mode):ADC_CONTINUOUS_OP
3、u8ChannelSelBitwise:指定输入通道,举例说明
u8ChannelSelBitwise=0x1(00000001b) 使能通道0
u8ChannelSelBitwise=0x19(00011001b)使能通道0、3、4
4、ClockSrc:指定ADC的时钟源,即设置ADC时钟源ADC_S,可选择
①. EXTERNAL_12MHZ
②.INTERNAL_PLL
③.INTERNAL_RC22MHZ=2
有个小问题:可能是新版的手册有误ADC_S=11 = 内部 22.1184 MHz 高速振荡器
其实ADC_S=1x就能选择内部 22.1184MHz 高速振荡器所以例程中INTERNAL_RC22MHZ=2是没错的。
5、u8AdcDivisor:确定ADC时钟预分频,即设置时钟分频寄存器ADC_NADC时钟频率= (ADC 时钟源频率) / (ADC_N+1)。
函数内部顺序执行的功能分别是:
1、复位ADC:外设复位控制寄存器2(IPRSTC2). ADC_RST P77
2、设置ADC时钟源寄存器ADC_S P162
3、设置ADC时钟分频寄存器_ADC_N P167
4、使能ADC时钟:APB 设备时钟使能控制寄存器APBCLK.ADC_EN P156
5、使能ADC:A/D 控制寄存器ADCR.ADEN P422
6、设置输入方式:单端输入或差分输入
7、设置操作模式:单一触发模式或单周期扫描模式或
连续扫描模式
8、选择ADC通道
9、设置相应通道的GPIO为ADC功能
总结:该函数功能已经涵盖了下列函数的功能
DrvADC_SetADCChannel//设置ADC通道
DrvADC_SetADCInputMode//设置输入模式
DrvADC_SetADCOperationMode//设置操作模式
DrvADC_SetADCClkSrc//设置ADC时钟源
DrvADC_SetADCDivisor//设置ADC时钟预分频
所以对该函数进行正确配置后几乎就完成了ADC的初始化
最后设置ADC->ADCR.DMOF =0;使AD转换的输出结果为无符号格式
二、DrvADC_StartConvert1、清除AD转换结束标志位ADF
outpw(ADC_ADSR, (inpw(ADC_ADSR)&(~0x7))|0x1);说明:不建议使用"ADC->ADSR.ADF= 1;"可能会清除了CMPF0 和CMPF12、设置AD转换开始标志:ADC->ADCR.ADST= 1;
下面是P430对ADF的描述,感觉很矛盾,在例程里也是这么操作的,所以想不通,
A/D 转换结束标志位
用以指示A/D转换已結束的状态标志位
以下两种条件下ADF置1.
1. 单一模式下,A/D 转换结束.
2. 扫描模式下,在所有指定通道的A/D转换结束.
写1可清除该标志
既然AD转换结束后能将ADF置1,怎么写1又可以清除该标志?不知哪位大哥可以解惑
三、DrvADC_IsConversionDone
查询ADC->ADSR.ADF是否为1,若为0返回FALSE,否则返回TRUE
四、int32_t DrvADC_GetConversionData(uint8_tu8ChannelNum)
返回相应通道的AD转换值
参考文件:
【1】NUC100 NUC120 Technical ReferenceManual SC V2.01
下载:NUC100 NUC120 系列产品的技术参考文档V2.01 - 中文版
【2】NUC100SeriesBSP_v1.05.002
下载:
NUC100Series BSP_CMSIS V1.05.002.7z 其他参考资料可到官方论坛或新塘官方网站下载:NUC100系列开发资源汇总(最后更新:2011-12-06)http://www.nuvoton-m0.com/forum.php?mod=viewthread&tid=1&extra=%26page%3D1&page=1
下面是调试用的源代码
#include "NUC1xx.h"
#include "DrvGPIO.h"
#include "DrvSYS.h"
#include "DrvADC.h"
#include "LCD4884.h"
void RCC_Configuration(void)
{
UNLOCKREG(); // 对写保护位操作时 需要一次向0x50000 0100写入 0x59,0x16,0x88,
DrvSYS_SetOscCtrl(E_SYS_XTL12M, 1);//与其 SYSCLK->PWRCON.XTL12M_EN = 1; 等同
// PWRCON寄存器(这些寄存器在上电复位到用户解锁定之前是锁定的)除了 BIT[6]位其他位都受写保护
// 解除这些需要向 0x50000 0100写入 0x59,0x16,0x88,
// 令PWRCON寄存器的BITP[0]为1(即设定12M外部晶振)
DrvSYS_Delay(5000); //while (DrvSYS_GetChipClockSourceStatus(E_SYS_XTL12M) != 1);//等待外部12MHZ晶振就绪
LOCKREG(); // 向“0x5000_0100”写入任何值,就可以重锁保护寄存器
}
void ADC_Configuration()
{
DrvADC_Open(ADC_SINGLE_END, ADC_SINGLE_OP, 2, EXTERNAL_12MHZ, 5); // ADC_SINGLE_END AD为单端输入模式
// ADC_SINGLE_OP 单一触发模式
// 2 GA1作为输入 模式输入通道使能
// EXTERNAL_12MHZ ADC时钟为 外部12MHZ
// 5 AD时钟频率 = ADC时钟/(5+1) = 2MHZ
ADC->ADCR.DMOF = 0; //转化结果无符号
}
void Set_System(void)
{
RCC_Configuration(); //配置系统时钟
ADC_Configuration(); //配置ADC
LCD_init();
}
int main(void)
{
int32_t i32AD_Data;
Set_System();
while(1)
{
DrvADC_StartConvert(); // 开启ADC转换
while(DrvADC_IsConversionDone()==FALSE); // 判断ADC是否转换结束
i32AD_Data = DrvADC_GetConversionData(1); //获取AD寄存器的值
LCD_clear(); //清屏幕
LCD_write_String(0,0,"Value:"); //LCD显示:Value
LCD_set_XY(0,1); //设置LCD光标位置
LCD_Disp_IntNum(i32AD_Data,'d',0); //显示AD寄存器的值
i32AD_Data = i32AD_Data*3380/0xfff; //修正AD转换的值为电压
//3380:参考电压为3.38v
//0xFFF:12位AD转换
LCD_set_XY(0,2);
LCD_Disp_IntNum(i32AD_Data,'d',0); //显示修正后的电压值
DrvSYS_Delay(5000000);
DrvSYS_Delay(5000000);
}
}
06-AD.rar
(202.93 KB)
|