[TOC]
*****
## **1. 写在前面**
经过前面的章节,可能我们可以看到从一个普通外设到驱动的编写,应用层的测试,其实对于同是ARM 的芯片,但却是不同系列,又或者操作系统不一致,如RTOS与Linux之前,但是对于一个硬件外设来说,它的寄存器、操作时序等,不会因为主机的不同也发生变化。那么,这篇文章也是帮助一些具有一定的硬件开发能力的童鞋,将之前的成果快速地转化到ARM Linux开发环境上来,帮助其更好的理解ARM Linux环境下的开发;又或者给只有ARM Linux驱动开发的童鞋提供多一条思路,对于一些比较成熟的外设模块,在没有相同平台的Demo的情况下,快速地参考已经有的其他平台的例子,快速完成功能开发。本章就以为**STM32**平台驱动温湿度**DHT11**为例,实现将单 片机驱动移植到ARM Linux下。
## **2. 硬件环境**
### **2.1 主控环境**
> 开发板:友善电子Nano Pi T4
> 主控:RK3399(ARM V8)
> OS:Linux version 4.4.143
> 编译器:aarch64-linux-gnu-gcc (gcc version 7.3.0)
### **2.2 外设环境**
DHT11 数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。
> 1. 供电电压:3-5.5V
>
> 2. 供电电流:最大2.5mA
>
> 3. 温度范围:0-50℃ 误差±2℃
>
> 4. 湿度范围:20-90%RH 误差±5%RH
>
> 5. 响应时间: 1/e(63%) 6-30s
>
> 6. 测量分辨率分别为 8bit(温度)、8bit(湿度)
>
> 7. 采样周期间隔不得低于1 秒钟
## **3.硬件接线**
由于DHT11采用了单总线的方式,所以输入输出都是在DATA线上完成了,典型的接线图如下,一般将DATA线接至CPU的某个IO口上。
![](https://box.kancloud.cn/00c578f9422f3f71c02b9eb3a540f3fa_552x340.jpg)
### **3.1 STM32接线**
:-: PE4---->DATA线
### **3.2 RK3399接线**
:-: GPIO1_A0---->DATA线
## **4. 移植原理**
对于DHT11这种外设来说,无非就是IO口上设为输入输出间切换,进而进行数据的读写操作。对IO的操作来说,STM32有提供一系列方便的库函数,如:
```
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
```
对于linux来说,同样,有一系列方便的接口,与STM32库函数不同的是,这些接口是经过高度抽象化的,不直接操作硬件。
```
enum of_gpio_flags {
OF_GPIO_ACTIVE_LOW = 0x1,
};
int of_get_named_gpio_flags(struct device_node *np, const char *propname,
int index, enum of_gpio_flags *flags);
int gpio_is_valid(int gpio);
int gpio_request(unsigned gpio, const char *label);
void gpio_free(unsigned gpio);
int gpio_direction_input(int gpio);
int gpio_direction_output(int gpio, int v);
```
除此之外,对于外设驱动来说,除了IO控制之外,还必须对时序有严格的要求,比如说延时,那么,对于一定MCU来说有类似STM32 滴答时钟实现的延时,其实,在linux驱