+
+
Posts List
  1. ADC
    1. 代码

电赛培训(二)ADC&CCS基本操作

ADC

模数转换器Analog-Digital Converter简称为ADC,顾名思义,就是把模拟信号通过采样转换为数字信号。在单片机中,我们经常会用到一些传感器来实现人机交互。像在上一节中最基础的按钮就是一个人机交互的例子,表面上是人对按钮施加压力,内部却是按钮所在电路的通断,再深入一点就是按钮电位的高低。不过在按钮这个例子中,我们只有高电平和低电平,就像0和1,是数字信号。但是其他的传感器,比如光敏电阻、拨码电位器这些,它们反映出来的数字并不是非0即1,而是有一定范围的数据,这时候就需要ADC了。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#include <msp430f5529.h>
#include <driverlib.h>
#include <main.h> //delay_ms
#include <LedLib.h>
#include <ButtonLib.h>
#include <UartLib.h>

// 全局变量定义区,在不同函数中都能使用
int flag=0; //做为ADC值更新的标志
int adcnum1=0; //ADC读取值

void ADC_Init(); //没有单独做成库,如果想打包成库,请参考自编库MyLib的写法
int main()
{
// 变量定义区
float vot = 0;

//关闭看门狗
WDT_A_hold(WDT_A_BASE);

// 硬件初始化
ledInit(LED_ALL);
BtnInit(S_ALL);
BtnInterruptInit(S_ALL);
UartA1_Init(); // 默认波特率为9600,在UartLib中可修改
ADC_Init(); //需要初始化!具体函数在main后面!
__bis_SR_register(GIE); //开启全局中断
// 建立一个大循环一直读取ADC数值
// 能不能直接在循环里读取而不用中断呢?just try it!
while (1)
{
//开始ADC12模块的采样和转换功能,注意第二个变量指的是应用于那个MEMORY,需要根据实际配置情况更改
//具体各个参量的功能,在adc12_a.h中查看,或库函数用户手册
ADC12_A_startConversion(ADC12_A_BASE,ADC12_A_MEMORY_0,ADC12_A_SINGLECHANNEL);
delay_ms(1000);
// 如果没有改变就不输出
if(flag)
{
uartA1_printf("ADC: %d ",adcnum1);
vot = (float)(adcnum1)/4096*3.3;
uartA1_printf("V: %d \r\n", (int)vot);
flag=0; //使用之后标志清零
}
//for Debugger
__no_operation();
}


//For debugger,不执行任何具体的操作
__no_operation();

return 0;
}

// ADC初始化函数,在本例中只对P6.5和MEMORY0进行了初始化,并将两者绑定在一起
// 其中的各个函数的使用和调用顺序都是根据官方example写的,是结构化的内容,在这个结构上改就行了
void ADC_Init()
{
//P6.0 对应放大器
//首先需要设置成外设功能(除了简单开关/读电平高低以外的功能都叫外设功能)才能使用
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P6,GPIO_PIN0);

/* 先初始化ADC12_A整个功能模块,不具体到哪个端口,参数使用默认的先不改
* 输入参数说明:
* Base address of ADC12_A Module
* Use internal ADC12_A bit as sample/hold signal to start conversion
* USE MODOSC 5MHZ Digital Oscillator as clock source
* Use default clock divider of 1
*/
ADC12_A_init(ADC12_A_BASE,
ADC12_A_SAMPLEHOLDSOURCE_SC,
ADC12_A_CLOCKSOURCE_ADC12OSC,
ADC12_A_CLOCKDIVIDER_1);
//打开ADC12_A功能模块
ADC12_A_enable(ADC12_A_BASE);

/* 设置ADC采样时钟,也先保持默认值,与采样速度有关,但采样过快精度会下降
* 输入参数说明:
* Base address of ADC12_A Module
* For memory buffers 0-7 sample/hold for 64 clock cycles
* For memory buffers 8-15 sample/hold for 4 clock cycles (default)
* Disable Multiple Sampling
*/
ADC12_A_setupSamplingTimer(ADC12_A_BASE,
ADC12_A_CYCLEHOLD_64_CYCLES,
ADC12_A_CYCLEHOLD_4_CYCLES,
ADC12_A_MULTIPLESAMPLESDISABLE);

/* 设置ADC工作端口,以及其对应的内存区域!这里要根据实际接线情况改!
* 如果要增加,就复制一段这样的代码加在下面,根据实际接线和需求改相应的变量。
* 输入参数说明:
* Base address of the ADC12_A Module
* 使用 memory buffer 0,可以从1~15
* 绑定 A0 到 memory buffer 0,绑定的MEMORY是随意的,而放大器接的P6.0对应A0
* 正参考电压Vref+ = AVcc 3.3V
* 负参考电压Vr- = AVss 0V
* Memory buffer 0 is not the end of a sequence
*/
ADC12_A_configureMemoryParam param = {0};
param.memoryBufferControlIndex = ADC12_A_MEMORY_0;
param.inputSourceSelect = ADC12_A_INPUT_A0;
param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;
param.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
ADC12_A_configureMemory(ADC12_A_BASE ,&param);

//对MEMORY0配置中断
ADC12_A_clearInterrupt(ADC12_A_BASE,ADC12IFG0);
ADC12_A_enableInterrupt(ADC12_A_BASE,ADC12IE0);


}

// ADC中断部分
// 其实也不一定需要用中断来读取ADC值,可以在main的大循环内使用ADC12_A_getResults读取,但在两次读取之间需要加一点延迟让ADC有准备时间!试一下这种方式吧!
// 微秒级别delay可以直接用__delay_cycles(x); x<32768,数据格式决定的
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=ADC12_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(ADC12_VECTOR)))
#endif
void ADC12_A_ISR (void)
{
// 关闭中断,以免影响运行
__disable_interrupt();
// 先读取ADC12IV的值,知道是哪个MEMORY被触发了,这一堆case,查寄存器手册吧
// 如果要使用多个ADC通道,需要在相应MEMORY的case里加值哟
switch (__even_in_range(ADC12IV,34)){
case 0: break; //Vector 0: No interrupt
case 2: break; //Vector 2: ADC overflow
case 4: break; //Vector 4: ADC timing overflow
case 6: //Vector 6: ADC12IFG0
flag=1; // 记录ADC值已经改变
adcnum1=ADC12_A_getResults(ADC12_A_BASE,ADC12_A_MEMORY_0); //获取特定MEMORY内保存ADC值的函数
// 读取完ADC值之后就可以写自己的语句实现相应的功能了
//set P8.1 On -> LED1
if (adcnum1>=682)
{
ledOff(LED_ALL);
ledOn(LED2);
if (adcnum1>=1364)
{
ledOn(LED3);
if (adcnum1>=2046)
{
ledOn(LED4);
if (adcnum1>=2728)
{
ledOn(LED5);
if (adcnum1>=3480)
{
ledOn(LED6);
}
}
}
}
}
else {
ledOff(LED_ALL);
}

case 8: break; //Vector 8: ADC12IFG1
case 10: break; //Vector 10: ADC12IFG2
case 12: break; //Vector 12: ADC12IFG3
case 14: break; //Vector 14: ADC12IFG4
case 16: break; //Vector 16: ADC12IFG5
case 18: break; //Vector 18: ADC12IFG6
case 20: break; //Vector 20: ADC12IFG7
case 22: break; //Vector 22: ADC12IFG8
case 24: break; //Vector 24: ADC12IFG9
case 26: break; //Vector 26: ADC12IFG10
case 28: break; //Vector 28: ADC12IFG11
case 30: break; //Vector 30: ADC12IFG12
case 32: break; //Vector 32: ADC12IFG13
case 34: break; //Vector 34: ADC12IFG14
default: break;
}
//执行完之后恢复中断
__enable_interrupt();
}

本文作者: rhinoc

本文链接: https://www.rhinoc.top/msp_2/

版权声明: 本博客所有文章除特别声明外,均采用BY-NC-SA 4.0国际许可协议,转载请注明。

打赏
Love U 3000
  • Through WeChat
  • Through Alipay