作者:周志强,华清远见嵌入式培训中心讲师。
1. GPIO操作原理
(1)LPC11C14处理器I/O控制原理:
LPC11C14处理器有0~3共4组输入/输出端口,其中第0~2组端口有11个寄存器,第3组端口有4个寄存器。
每组端口都有复用的功能,例如可以作为输入/输出端口,还可以定义为I2C接口功能,用户可以通过软件配置寄存器来满足不同系统和书籍的需要。在运行主程序之前,必须先对每一个用到的引脚的功能进行设置。如果某些引脚的复用功能没有使用,那么可以先将该引脚设置为通用的I/O端口。
I/O端口的配置过程类似,因此接下来来讲解一下端口配置的方法。
下表列出了几个寄存器的定义:
①PIO3_0
对应位 |
标志 |
值 |
相关描述 |
复位值 |
2 : 0 |
功能 |
|
选择引脚功能 |
000 |
|
0x0 |
作为GPIO引脚PIO3_0 |
|
|
0x1 |
选择/DTR功能 |
|
||
4 : 3 |
模式 |
|
选择功能模式(上拉或下拉电阻控制) |
10 |
|
0x0 |
无反应(无上拉/下拉使能) |
|
|
0x1 |
下拉使能 |
|
||
0x2 |
上拉使能 |
|
||
0x3 |
重复模式 |
|
||
5 |
滞后 |
|
滞后 |
0 |
|
0 |
禁止 |
|
|
1 |
使能 |
|
||
7 : 6 |
— |
— |
保留 |
11 |
31 : 8 |
— |
— |
保留 |
0 |
②PIO3_2
对应位 | 标志 | 值 | 相关描述 |
复位值 |
2 : 0 |
功能 |
|
选择引脚功能 |
000 |
|
0x0 |
作为GPIO引脚PIO3_2 |
|
|
0x1 |
选择/DCD功能 |
|
||
4 : 3 |
模式 |
|
选择功能模式(上拉或下拉电阻控制) |
10 |
|
0x0 |
无反应(无上拉/下拉使能) |
|
|
0x1 |
下拉使能 |
|
||
0x2 |
上拉使能 |
|
||
0x3 |
重复模式 |
|
||
5 |
滞后 |
|
滞后 |
0 |
|
0 |
禁止 |
|
|
1 |
使能 |
|
||
7 : 6 |
— |
— |
保留 |
11 |
31 : 8 |
— |
— |
保留 |
0 |
在硬件实现上,我们已经将PIO3_0引脚连接到LED1的控制引脚,PIO3_1连接到LED2的控制引脚上。如图7-18所示:
图7-18
(2)温/湿度传感器及其信息采集原理
在我们的实验开发平台上,我们使用的是DHT11温/湿度传感器作为信息温度和湿度信息采集的来源。
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温数度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。
其亮点在于:成本低、长期稳定、相对湿度和温度测量、品质卓越、超快响应、抗干扰能力强、超长的信号传输距离、数字信号输出、精确校准。可以应用在暖通空调、除湿器、湿度调节器、医疗等相关领域之中。
电路图如图7-19所示。
图7-19 DHT11电路图
信息采集的原理为:
温湿度信息的获得是通过M0上的DHT11数字温湿度传感器实现的。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。DHT11期间采用简单的单总线通信,系统中的数据交换、控制均由单总线完成。
单总线传送数据位定义:
DATA用于微处理器于DHT11之间的通讯于同步,采用单总线数据格式,一次传送40位数据,高位先出数据格式是:
8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit检验位(检验位的值为前四者和的低8位)。
数据时序图:
用户主机(MCU)发送一次开始信号后,DHT11从低功耗模式转换到高速模式,待主机开始信号结束后,DHT11发送响应信号,送出40bit数据,并触发一次信息采集,信号发送如图:
图7-20 数据时序图
读取数据步骤:
1、DHT11上电后会测试环境的温度和湿度,并且记录数。数据线被DHT11上拉电阻拉高,DATA引脚处于输入状态。
2、上电后设置PIO3_2为输出方式,并且输出低电平,数据总线被IO拉低。等待大于18ms后,设置PIO2_3引脚为输入状态,并且设置上拉电阻,将DATA数据线拉高;
3、DHT11的DATA引脚检测到外部的低电平的信号后,延迟后输出80us低电平作为应答信号,和80微妙的高电平信号作为通知处理准备接收数据的开始信号。
4、处理器的IO接到DHT11的应答信号后,又接到准备接收的开始信号后,开始接收40位数据。数据是以50us的低电平和26-28us的高电平作为数据‘0’,数据是以50us的低电平和70us的高电平作为数据‘1’。
5、DHT11发送完40位的数据后,继续输出50us的低电平。然后DATA引脚转为输入状态,上拉电阻拉高数据线。DHT11重新检测数据并记录,准备下次发送信号。
2.GPIO操作步骤
(1)准备好实验环境,设置相应的选项;
(2)使用Co-Linker仿真器将实验程序下载到FS11C14开发板中;
(3)启动FS11C14开发板,将功能拨至温/湿度信息采集区域,即可获得相关数据;
(4)退出系统。
3. GPIO参考程序及说明
(1)GPIO初始化函数GPIOInit()。
该函数用来初始化GPIO,使能GPIO中断处理函数。函数的实现程序代码如下:
void GPIOInit( void )
{
/* Enable AHB clock to the GPIO domain. */
LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6);
#ifdef __JTAG_DISABLED
LPC_IOCON->R_PIO1_1 &= ~0x07;
LPC_IOCON->R_PIO1_1 |= 0x01;
#endif
/* Set up NVIC when I/O pins are configured as external interrupts. */
NVIC_EnableIRQ(EINT0_IRQn);
NVIC_EnableIRQ(EINT1_IRQn);
NVIC_EnableIRQ(EINT2_IRQn);
NVIC_EnableIRQ(EINT3_IRQn);
return;
}
(2)GPIO位设置函数void GPIOSetValue( uint32_t portNum, uint32_t bitPosi, uint32_t bitVal )。
该函数用于对GPIO的某一位进行置位,输入参数分别为portNum,bitPosi,bitVal,第一和第二个参数决定所要进行设置的位置,bitVal定义了位的内容。该函数的程序代码如下:
void GPIOSetValue( uint32_t portNum, uint32_t bitPosi, uint32_t bitVal )
{
LPC_GPIO[portNum]->MASKED_ACCESS[(1<<bitPosi)] = (bitVal<<bitPosi);
}
(3)GPIO属性设置函数void GPIOSetDir( uint32_t portNum, uint32_t bitPosi, uint32_t dir )。
该函数对GPIO的某一个引脚进行输入/出属性的设置。Dir决定了数据传输的方向,若设置为1,则为输出;设置为0,则为输入。程序代码如下:
void GPIOSetDir( uint32_t portNum, uint32_t bitPosi, uint32_t dir )
{
if(dir)
LPC_GPIO[portNum]->DIR |= 1<<bitPosi;
else
LPC_GPIO[portNum]->DIR &= ~(1<<bitPosi);
}
(4)温湿度信息采集演示
在主程序main.c中通过如下的程序选择了温/湿度信息采集的功能:
case 5:
printf("\r\n\r\nTemperature & Humidity Test");
Temp_Hum_Test(); //执行温/湿度信息的采集
break;
在函数Temp_Hum_Test中通过调用Read_Temp_Hum函数进行实现。Read_Temp_Hum函数的具体表现为:
uint32_t Read_Temp_Hum(uint8_t *temp, uint8_t *hum)
{
uint32_t cnt_last;
...
p3_2_counter = 0;
cnt_last = p3_2_counter;
GPIOIntDisable(PORT3, 2); //取消中断屏蔽
GPIOSetDir(PORT3, 2, 1); // 设置PIO3_2为输出模式
GPIOSetValue(PORT3, 2, 0);
delay_ms(30);
GPIOSetValue(PORT3, 2, 1);
GPIOSetDir(PORT3, 2, 0);
GPIOSetInterrupt(PORT3, 2, 0, 0, 0); //设置中断模式
GPIOIntEnable(PORT3, 2); //使能中断掩码
for(i=0; i<3; i++)
{
GPIOSetInterrupt(PORT3, 2, 0, 0, i&0x01);
while(p3_2_counter == cnt_last);
cnt_last = p3_2_counter;
}
for(i=0; i<40; i++)
{
GPIOSetInterrupt(PORT3, 2, 0, 0, 1);
while(p3_2_counter == cnt_last);
cnt_last = p3_2_counter;
tc1 = p3_2_tc;
GPIOSetInterrupt(PORT3, 2, 0, 0, 0);
while(p3_2_counter == cnt_last);
cnt_last = p3_2_counter;
...
{
chksum <<= 1;
if(tc >= 2328)
chksum |= 0x01;
}
}
GPIOSetInterrupt(PORT3, 2, 0, 0, 1);
while(p3_2_counter == cnt_last);
GPIOIntDisable(PORT3, 2);
*temp = temp_10;
*(temp+1) = temp_01;
*hum = hum_10;
*(hum+1) = hum_01;
//校验和的求解
chk = hum_10;
chk += hum_01;
chk += temp_10;
chk += temp_01;
if(chk == chksum)
return 1;
else
return 0;
}