“第022课 传感器”的版本间的差异
第1行: | 第1行: | ||
=第001节_光敏电阻的使用= | =第001节_光敏电阻的使用= | ||
+ | 这节课我们开始讲的传感器,有光敏电阻、DH11温湿度传感器、DS18B20温度传感器、HS0038红外接收器。 | ||
+ | |||
+ | 首先介绍光敏电阻传感器。 | ||
+ | |||
+ | 光敏电阻有一个特点,就是它的阻值随光照强度变化而变化, | ||
+ | |||
+ | 看一下它的原理图,R5是一个普通电阻,LAS1是光敏电阻,它们串联组成一个分压电路, | ||
+ | |||
+ | LAS1阻值变化,将会导致中间RES_AO测得的电压发生变化。 | ||
+ | |||
+ | [[File:chapter22_lesson1_001.png|800px]] | ||
+ | |||
+ | 这个电路图有点绕,画一个示意图如下: | ||
+ | |||
+ | [[File:chapter22_lesson1_002.png|800px]] | ||
+ | |||
+ | 使用ADC测量A点的电压,可以得知LAS1的变化情况,这里的测量是一个模拟信号。 | ||
+ | |||
+ | |||
+ | 现在假如需要这个光敏系统在光照大于/小于某个值时,发出中断,怎么办呢? | ||
+ | |||
+ | 这里就需要再加一个比较的电路,B处的电压是可调电阻得到的电压,可以通过调节电阻进行变化。A、B两个电压最后接在一个比较器的“正负端”,当A>B时,输出1,反之输出0。 | ||
+ | |||
+ | 通过调节可调电阻,可以实现对比较阈值的控制。 | ||
+ | |||
+ | 现在这个电路就即可得到模拟信号和数字信号。 | ||
+ | |||
+ | |||
+ | 现在就可以开始写程序了,复制前面024的代码为025_sensors,这是这一章的第一个项目,再创建个001_photoresistor文件夹,将代码都放进去。 | ||
+ | |||
+ | 再创建一个sensors文件夹用来放本课的所有传感器代码,然后再创建photoresistor文件夹放本节课代码,再在里面创建photoresistor.c。 | ||
+ | |||
+ | 在代码里面,我们要做两件事: | ||
+ | |||
+ | :: 1.启动ADC,读出AIN1电压值; | ||
+ | :: 2.注册中断,当光线强度超过或小于某个阈值时,产生中断; | ||
+ | |||
+ | 打开工程里的adc代码,原来的adc_init,只初始化了adc0,现在我们要用AIN1,修改下代码,传入个参数就能初始化对应的AIN: | ||
+ | |||
+ | <syntaxhighlight lang="c" > | ||
+ | void adc_init(int channel) | ||
+ | { | ||
+ | /* [15] : ECFLG, 1 = End of A/D conversion | ||
+ | * [14] : PRSCEN, 1 = A/D converter prescaler enable | ||
+ | * [13:6]: PRSCVL, adc clk = PCLK / (PRSCVL + 1) | ||
+ | * [5:3] : SEL_MUX, 000 = AIN 0 | ||
+ | * [2] : STDBM | ||
+ | * [0] : 1 = A/D conversion starts and this bit is cleared after the startup. | ||
+ | */ | ||
+ | ADCCON = (1<<14) | (49<<6) | (channel<<3); | ||
+ | |||
+ | ADCDLY = 0xff; | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | 后面的adc_read_ain0只能读取AIN0的数据,现在修改一下,传入个通道参数,就能读取对应通道的ADC值: | ||
+ | |||
+ | <syntaxhighlight lang="c" > | ||
+ | int adc_read(int channel) | ||
+ | { | ||
+ | adc_init(channel); | ||
+ | |||
+ | /* 启动ADC */ | ||
+ | ADCCON |= (1<<0); | ||
+ | |||
+ | while (!(ADCCON & (1<<15))); /* 等待ADC结束 */ | ||
+ | |||
+ | return ADCDAT0 & 0x3ff; | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | 修改了这两个函数,原来的adc_test函数里调用的adc读取函数也要对应进行修改。 | ||
+ | |||
+ | |||
+ | 参考这个adc_test,编写photoresistor_test函数。 | ||
+ | |||
+ | 需要修改的内容并不多,首先是修改adc_read参数,将通道0改为通道1。 | ||
+ | |||
+ | 然后我们想同时再把AIN0上的滑动电阻对应的电压也读出来,因此再做一次ADC0读取的操作。 | ||
+ | |||
+ | <syntaxhighlight lang="c" > | ||
+ | void photoresistor_test(void) | ||
+ | { | ||
+ | int val, val0; | ||
+ | double vol, vol0; | ||
+ | int m, m0; /* 整数部分 */ | ||
+ | int n, n0; /* 小数部分 */ | ||
+ | |||
+ | //adc_init(); | ||
+ | |||
+ | while (1) | ||
+ | { | ||
+ | val = adc_read(1); | ||
+ | vol = (double)val/1023*3.3; /* 1023----3.3v */ | ||
+ | m = (int)vol; /* 3.01, m = 3 */ | ||
+ | vol = vol - m; /* 小数部分: 0.01 */ | ||
+ | n = vol * 1000; /* 10 */ | ||
+ | |||
+ | val0 = adc_read(0); | ||
+ | vol0 = (double)val0/1023*3.3; /* 1023----3.3v */ | ||
+ | m0 = (int)vol0; /* 3.01, m = 3 */ | ||
+ | vol0 = vol0 - m0; /* 小数部分: 0.01 */ | ||
+ | n0 = vol0 * 1000; /* 10 */ | ||
+ | |||
+ | /* 在串口上打印 */ | ||
+ | printf("photoresistor vol: %d.%03dv, compare to threshold %d.%03dv\r", m, n, m0, n0); /* 3.010v */ | ||
+ | |||
+ | /* 在LCD上打印 */ | ||
+ | //fb_print_string(); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | 以上就完成了我们的第一个目标。 | ||
+ | |||
+ | |||
+ | 现在开始做第二个目标,注册中断放在interrupt.c里实现。 | ||
+ | |||
+ | 硬件上RES_DO是EINT15。我们可以仿照之前的按键中断来编写本次的中断。 | ||
+ | |||
+ | 先分析一下中断,如图: | ||
+ | |||
+ | [[File:chapter22_lesson1_003.png|800px]] | ||
+ | |||
+ | |||
+ | GPG7作为中断引脚,它会先经过外部中断EINTMASK寄存器,才能进入到中断控制器。 | ||
+ | |||
+ | 所以,需要做以下操作: | ||
+ | |||
+ | *①首先初始化: | ||
+ | :: a.GPG7配置为中断引脚; | ||
+ | :: b.设置中端触发方式:双边沿触发; | ||
+ | :: c.设置EINTMASK使能中断; | ||
+ | |||
+ | *②中断处理: | ||
+ | :: a.分辨:读EINTPEND; | ||
+ | :: b.读GPG7; | ||
+ | |||
+ | 在原来的key_eint_init函数里配置GPG7为中断引脚: | ||
+ | |||
+ | <syntaxhighlight lang="c" > | ||
+ | /* 配置GPG7为中断引脚, 用于光敏电阻 */ | ||
+ | GPGCON &= ~((3<<14)); | ||
+ | GPGCON |= ((2<<14)); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | 然后设置中端触发方式:双边沿触发 | ||
+ | <syntaxhighlight lang="c" > | ||
+ | /* 设置中断触发方式: 双边沿触发 */ | ||
+ | EXTINT0 |= (7<<0) | (7<<8); /* S2,S3 */ | ||
+ | EXTINT1 |= (7<<12); /* S4 */ | ||
+ | EXTINT2 |= (7<<12); /* S5 */ | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | 最后再使能中断: | ||
+ | <syntaxhighlight lang="c" > | ||
+ | /* 使能中断GPG7/EINT15, 用于光敏电阻 */ | ||
+ | EINTMASK &= ~((1<<15)); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | 修改key_eint_irq中断处理函数,先判断是哪个中断产生,再读取电平,打印。 | ||
+ | <syntaxhighlight lang="c" > | ||
+ | else if (val & (1<<15)) /* eint15, 用于光敏电阻 */ | ||
+ | { | ||
+ | if (val2 & (1<<7)) | ||
+ | { | ||
+ | printf("\n\rphotoresistor dark!\n\r"); | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | printf("\n\rphotoresistor light!\n\r"); | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | 至此,代码就写完了,最后还要修改对应的Makefile和主函数。 | ||
+ | |||
=第002节_高精度延时函数= | =第002节_高精度延时函数= | ||
=第003节_DHT11温湿度传感器的使用= | =第003节_DHT11温湿度传感器的使用= |
2018年3月27日 (二) 18:21的版本
目录
第001节_光敏电阻的使用
这节课我们开始讲的传感器,有光敏电阻、DH11温湿度传感器、DS18B20温度传感器、HS0038红外接收器。
首先介绍光敏电阻传感器。
光敏电阻有一个特点,就是它的阻值随光照强度变化而变化,
看一下它的原理图,R5是一个普通电阻,LAS1是光敏电阻,它们串联组成一个分压电路,
LAS1阻值变化,将会导致中间RES_AO测得的电压发生变化。
这个电路图有点绕,画一个示意图如下:
使用ADC测量A点的电压,可以得知LAS1的变化情况,这里的测量是一个模拟信号。
现在假如需要这个光敏系统在光照大于/小于某个值时,发出中断,怎么办呢?
这里就需要再加一个比较的电路,B处的电压是可调电阻得到的电压,可以通过调节电阻进行变化。A、B两个电压最后接在一个比较器的“正负端”,当A>B时,输出1,反之输出0。
通过调节可调电阻,可以实现对比较阈值的控制。
现在这个电路就即可得到模拟信号和数字信号。
现在就可以开始写程序了,复制前面024的代码为025_sensors,这是这一章的第一个项目,再创建个001_photoresistor文件夹,将代码都放进去。
再创建一个sensors文件夹用来放本课的所有传感器代码,然后再创建photoresistor文件夹放本节课代码,再在里面创建photoresistor.c。
在代码里面,我们要做两件事:
- 1.启动ADC,读出AIN1电压值;
- 2.注册中断,当光线强度超过或小于某个阈值时,产生中断;
打开工程里的adc代码,原来的adc_init,只初始化了adc0,现在我们要用AIN1,修改下代码,传入个参数就能初始化对应的AIN:
void adc_init(int channel)
{
/* [15] : ECFLG, 1 = End of A/D conversion
* [14] : PRSCEN, 1 = A/D converter prescaler enable
* [13:6]: PRSCVL, adc clk = PCLK / (PRSCVL + 1)
* [5:3] : SEL_MUX, 000 = AIN 0
* [2] : STDBM
* [0] : 1 = A/D conversion starts and this bit is cleared after the startup.
*/
ADCCON = (1<<14) | (49<<6) | (channel<<3);
ADCDLY = 0xff;
}
后面的adc_read_ain0只能读取AIN0的数据,现在修改一下,传入个通道参数,就能读取对应通道的ADC值:
int adc_read(int channel)
{
adc_init(channel);
/* 启动ADC */
ADCCON |= (1<<0);
while (!(ADCCON & (1<<15))); /* 等待ADC结束 */
return ADCDAT0 & 0x3ff;
}
修改了这两个函数,原来的adc_test函数里调用的adc读取函数也要对应进行修改。
参考这个adc_test,编写photoresistor_test函数。
需要修改的内容并不多,首先是修改adc_read参数,将通道0改为通道1。
然后我们想同时再把AIN0上的滑动电阻对应的电压也读出来,因此再做一次ADC0读取的操作。
void photoresistor_test(void)
{
int val, val0;
double vol, vol0;
int m, m0; /* 整数部分 */
int n, n0; /* 小数部分 */
//adc_init();
while (1)
{
val = adc_read(1);
vol = (double)val/1023*3.3; /* 1023----3.3v */
m = (int)vol; /* 3.01, m = 3 */
vol = vol - m; /* 小数部分: 0.01 */
n = vol * 1000; /* 10 */
val0 = adc_read(0);
vol0 = (double)val0/1023*3.3; /* 1023----3.3v */
m0 = (int)vol0; /* 3.01, m = 3 */
vol0 = vol0 - m0; /* 小数部分: 0.01 */
n0 = vol0 * 1000; /* 10 */
/* 在串口上打印 */
printf("photoresistor vol: %d.%03dv, compare to threshold %d.%03dv\r", m, n, m0, n0); /* 3.010v */
/* 在LCD上打印 */
//fb_print_string();
}
以上就完成了我们的第一个目标。
现在开始做第二个目标,注册中断放在interrupt.c里实现。
硬件上RES_DO是EINT15。我们可以仿照之前的按键中断来编写本次的中断。
先分析一下中断,如图:
GPG7作为中断引脚,它会先经过外部中断EINTMASK寄存器,才能进入到中断控制器。
所以,需要做以下操作:
- ①首先初始化:
- a.GPG7配置为中断引脚;
- b.设置中端触发方式:双边沿触发;
- c.设置EINTMASK使能中断;
- ②中断处理:
- a.分辨:读EINTPEND;
- b.读GPG7;
在原来的key_eint_init函数里配置GPG7为中断引脚:
/* 配置GPG7为中断引脚, 用于光敏电阻 */
GPGCON &= ~((3<<14));
GPGCON |= ((2<<14));
然后设置中端触发方式:双边沿触发
/* 设置中断触发方式: 双边沿触发 */
EXTINT0 |= (7<<0) | (7<<8); /* S2,S3 */
EXTINT1 |= (7<<12); /* S4 */
EXTINT2 |= (7<<12); /* S5 */
最后再使能中断:
/* 使能中断GPG7/EINT15, 用于光敏电阻 */
EINTMASK &= ~((1<<15));
修改key_eint_irq中断处理函数,先判断是哪个中断产生,再读取电平,打印。
else if (val & (1<<15)) /* eint15, 用于光敏电阻 */
{
if (val2 & (1<<7))
{
printf("\n\rphotoresistor dark!\n\r");
}
else
{
printf("\n\rphotoresistor light!\n\r");
}
}
至此,代码就写完了,最后还要修改对应的Makefile和主函数。