[菜农助学交流] 【第四批】笔记五——ADC初始化程序解析

[复制链接]
6535|5
 楼主| zxcscm 发表于 2012-2-15 22:34 | 显示全部楼层 |阅读模式
本帖最后由 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)
使能通道034

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
、使能ADCA/D 控制寄存器ADCR.ADEN  P422
6
、设置输入方式:单端输入或差分输入
7
、设置操作模式:单一触发模式单周期扫描模式
连续扫描模式
8
、选择ADC通道
9
、设置相应通道的GPIOADC功能

总结:该函数功能已经涵盖了下列函数的功能
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;
下面是P430ADF的描述,感觉很矛盾,在例程里也是这么操作的,所以想不通,
A/D 转换结束标志位

用以指示A/D转换已結束的状态标志位

以下两种条件下ADF1.
1.  单一模式下,A/D 转换结束.
2.  扫描模式下,在所有指定通道的A/D转换结束.
1可清除该标志

既然AD转换结束后能将ADF1,怎么写1又可以清除该标志?不知哪位大哥可以解惑

三、DrvADC_IsConversionDone

查询ADC->ADSR.ADF是否为1,若为0返回FALSE,否则返回TRUE

四、int32_t DrvADC_GetConversionData(uint8_tu8ChannelNum)

返回相应通道的AD转换值


参考文件:
1NUC100 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-06http://www.nuvoton-m0.com/forum.php?mod=viewthread&tid=1&extra=%26page%3D1&page=1

下面是调试用的源代码

  1. #include "NUC1xx.h"
  2. #include "DrvGPIO.h"
  3. #include "DrvSYS.h"
  4. #include "DrvADC.h"
  5. #include "LCD4884.h"

  6. void RCC_Configuration(void)
  7. {
  8.    UNLOCKREG();                                  // 对写保护位操作时 需要一次向0x50000 0100写入 0x59,0x16,0x88,
  9.    DrvSYS_SetOscCtrl(E_SYS_XTL12M, 1);//与其 SYSCLK->PWRCON.XTL12M_EN = 1; 等同
  10.                                       // PWRCON寄存器(这些寄存器在上电复位到用户解锁定之前是锁定的)除了 BIT[6]位其他位都受写保护
  11.                                           // 解除这些需要向 0x50000 0100写入 0x59,0x16,0x88,
  12.                                                                       // 令PWRCON寄存器的BITP[0]为1(即设定12M外部晶振)
  13.    DrvSYS_Delay(5000);                //while (DrvSYS_GetChipClockSourceStatus(E_SYS_XTL12M) != 1);//等待外部12MHZ晶振就绪
  14.    LOCKREG();                                  // 向“0x5000_0100”写入任何值,就可以重锁保护寄存器
  15. }

  16. void ADC_Configuration()
  17. {

  18.     DrvADC_Open(ADC_SINGLE_END, ADC_SINGLE_OP, 2, EXTERNAL_12MHZ, 5);         //  ADC_SINGLE_END  AD为单端输入模式
  19.                                                                                                                                                   //  ADC_SINGLE_OP         单一触发模式
  20.                                                                                                                                                  //  2         GA1作为输入         模式输入通道使能
  21.                                                                                                                                                  //  EXTERNAL_12MHZ   ADC时钟为 外部12MHZ
  22.                                                                                                                                                  //  5   AD时钟频率 = ADC时钟/(5+1)        = 2MHZ
  23.                                                                                                      
  24.     ADC->ADCR.DMOF = 0;                                                                                                         //转化结果无符号

  25. }

  26. void Set_System(void)
  27. {
  28.     RCC_Configuration();       //配置系统时钟
  29.   
  30.     ADC_Configuration();       //配置ADC
  31.   
  32.     LCD_init();
  33. }

  34. int main(void)
  35. {
  36.     int32_t i32AD_Data;
  37.    
  38.     Set_System();
  39.    
  40.     while(1)
  41.     {
  42.         DrvADC_StartConvert();                      //  开启ADC转换
  43.             while(DrvADC_IsConversionDone()==FALSE);    //  判断ADC是否转换结束
  44.         
  45.         i32AD_Data = DrvADC_GetConversionData(1);   //获取AD寄存器的值

  46.         LCD_clear();                                 //清屏幕               
  47.         LCD_write_String(0,0,"Value:");     //LCD显示:Value
  48.         LCD_set_XY(0,1);                    //设置LCD光标位置
  49.         LCD_Disp_IntNum(i32AD_Data,'d',0);  //显示AD寄存器的值
  50.         
  51.         i32AD_Data = i32AD_Data*3380/0xfff; //修正AD转换的值为电压
  52.                                             //3380:参考电压为3.38v
  53.                                             //0xFFF:12位AD转换
  54.         LCD_set_XY(0,2);
  55.         LCD_Disp_IntNum(i32AD_Data,'d',0);  //显示修正后的电压值
  56.         
  57.         DrvSYS_Delay(5000000);
  58.         DrvSYS_Delay(5000000);
  59.     }
  60. }




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
呆板书生 发表于 2012-2-16 08:32 | 显示全部楼层
既然AD转换结束后能将ADF置1,怎么写1又可以清除该标志?不知哪位大哥可以解惑

读和写其实是两个不同的寄存器,只是地址相同
 楼主| zxcscm 发表于 2012-2-22 12:48 | 显示全部楼层
明白了,哈哈哈  谢谢!
john_lee 发表于 2012-2-22 19:39 | 显示全部楼层
顶楼主,有质量的好帖。
dong_abc 发表于 2012-2-22 20:34 | 显示全部楼层
既然AD转换结束后能将ADF置1,怎么写1又可以清除该标志?不知哪位大哥可以解惑

读和写其实是两个不同的寄存器,只是地址相同
呆板书生 发表于 2012-2-16 08:32


是啊,一直不知道为什么!
 楼主| zxcscm 发表于 2012-2-24 22:50 | 显示全部楼层
4# john_lee 多谢李老师的肯定
您需要登录后才可以回帖 登录 | 注册

本版积分规则

5

主题

628

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部