GPIO 开漏输出的时候,也可以读取外部的数据

今天的实验是,能不能设置好引脚之后,这个引脚既能输出,又能输入呢?比如DHT11的数据引脚

1.按键的引脚设置为开漏输出,cpu能读取到正确的按键动作

查询方式和中断方式都可以正常工作(按键连接地,按下时是低电平)

 

 

但是有个非常重要的问题一定要注意,该引脚连接的外部设备在cpu输出高电平的时候是不是需要比较大的电流

 

 

2.接下来,我们做一下DHT11的实验,也能获得成功,读取位数据的时候,没有修改io端口的模式

 

 

 

实验代码如下:

#include <stm32f4xx.h>

#include "delay.h"

//华清远见stm32开发板,DHT11数据引脚连接的是PA3引脚

 

 

 

 

//初始化函数

//主要是引脚的配置

void DHT11_init(void)

{        

GPIO_InitTypeDef GPIO_InitStruct;  //定义一个结构体,并且配置内容,GPIO_Init会根据这个结构体的内容配置我的io端口

 

//1.GPIO端口时钟使能

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);    //之后操作任何外部设备,都要使能时钟

 

//2.配置io端口输出模式(PA3)

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;    //模式,输出模式

GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3 ;     //哪一个或者哪几个   0x100 | 0x200 = 0x300

GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;   //输出速度

GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;    //上拉下拉是否需要

 

GPIO_Init(GPIOA, &GPIO_InitStruct);

 

//引脚默认输出高电平

GPIO_SetBits(GPIOA, GPIO_Pin_3);

 

}

 

 

 

uint8_t DHT11_start(void)

{

uint8_t cnt = 0;

//发送起始信号        

GPIO_ResetBits(GPIOA, GPIO_Pin_3);    //低电平   18ms

delay_ms(18);

GPIO_SetBits(GPIOA, GPIO_Pin_3);    //高电平   20-40us

delay_us(30);                       //中间值 30us

 

while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3)  == Bit_SET)  //等待DHT11响应,拉低电平

cnt = 0;

while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3)  == Bit_RESET)

{

cnt ++;

if(cnt > 100)

{

return 1;  //出错,DHT11没有响应

}        

delay_us(1);

}

 

cnt = 0;

while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3)  == Bit_SET)   //拉高 80us

{

cnt ++;

if(cnt > 100)

{

return 1;  //出错,DHT11没有响应

}        

delay_us(1);

}

 

return 0;

}

 

 

 

static uint8_t read_bit(void)

{

uint8_t cnt = 0;   //大约

 

while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3)  == Bit_RESET);  //等待低电平变高

 

while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3)  == Bit_SET)   //拉高 80us

{

cnt ++;        //大约延时40us

 

if(cnt > 2)

{

while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3)  == Bit_SET);  //等待高电平变低

return 1;                

}        

delay_us(20);

 

}

return 0;

 

}

 

 

 

 

 

uint8_t DHT11_Read_Byte(void)

{

uint8_t dat = 0;

 

uint8_t i;

 

for(i=0;i<8;i++)

{        

dat <<= 1 ;  //因为最后一位不需要左移,

dat |= read_bit();

 

}

 

return dat;

}

 

 

uint8_t DHT11_Read_Data(uint8_t *tmp,uint8_t *humi)

{

uint8_t recv;

uint8_t buf[5];

uint8_t i;

 

recv =  DHT11_start();    //发送起始信号

if(recv == 1)   //出错了

{

return 1;

}

 

for(i=0;i<5;i++)

{

buf[i] = DHT11_Read_Byte();

}

 

if(buf[0]+buf[1]+buf[2]+buf[3] == buf[4])

{

*tmp = buf[2];

*humi = buf[0];

return 0;

}

 

return 1;    //出错

}

 

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在 GD32 上采集外部上升沿信号,可以使用定时器捕获模式。具体步骤如下: 1. 初始化 GPIO 口为输入模式。 2. 初始化定时器为捕获模式,并设置触发源为外部上升沿。 3. 在定时器触发后,通过 DMA 读取 GPIO数据。 下面是示例代码: ```c #include "gd32f30x.h" #define BUFFER_SIZE 100 uint16_t g_data_buffer[BUFFER_SIZE]; uint8_t g_dma_transfer_complete = 0; void gpio_init(void) { /* Enable the GPIOB clock */ rcu_periph_clock_enable(RCU_GPIOB); /* Configure PB13 as input */ gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_13); } void timer_init(void) { /* Enable the TIMER1 clock */ rcu_periph_clock_enable(RCU_TIMER1); /* Configure TIMER1 channel 1 as input capture */ timer_ic_parameter_struct timer_icinitpara; timer_icinitpara.icpolarity = TIMER_IC_POLARITY_RISING; timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI; timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1; timer_icinitpara.icfilter = 0; timer_input_capture_config(TIMER1, TIMER_CH_1, &timer_icinitpara); /* Configure TIMER1 as up counter with a period of 0xFFFF and a frequency of 72 MHz */ timer_parameter_struct timer_initpara; timer_initpara.prescaler = 0; timer_initpara.alignedmode = TIMER_COUNTER_EDGE; timer_initpara.counterdirection = TIMER_COUNTER_UP; timer_initpara.period = 0xFFFF; timer_initpara.clockdivision = TIMER_CKDIV_DIV1; timer_init(TIMER1, &timer_initpara); /* Enable TIMER1 */ timer_enable(TIMER1); } void dma_init(void) { /* Enable the DMA clock */ rcu_periph_clock_enable(RCU_DMA); /* Configure DMA channel 1 */ dma_parameter_struct dma_initpara; dma_initpara.direction = DMA_PERIPHERAL_TO_MEMORY; dma_initpara.peripheral_addr = (uint32_t)&GPIO_BOP(GPIOB); dma_initpara.memory_addr = (uint32_t)g_data_buffer; dma_initpara.number = BUFFER_SIZE; dma_initpara.peripheral_burst = DMA_BURST_SINGLE; dma_initpara.memory_burst = DMA_BURST_SINGLE; dma_initpara.peripheral_width = DMA_PERIPHERAL_WIDTH_16BIT; dma_initpara.memory_width = DMA_MEMORY_WIDTH_16BIT; dma_initpara.priority = DMA_PRIORITY_ULTRA_HIGH; dma_initpara.m2m = DMA_M2M_DISABLE; dma_init(DMA1, DMA_CH1, &dma_initpara); /* Enable DMA channel 1 transfer complete interrupt */ dma_interrupt_enable(DMA1, DMA_CH1, DMA_INT_FTF); /* Enable DMA channel 1 */ dma_channel_enable(DMA1, DMA_CH1); } void dma1_channel1_isr(void) { if (dma_interrupt_flag_get(DMA1, DMA_CH1, DMA_INT_FLAG_FTF)) { g_dma_transfer_complete = 1; dma_interrupt_flag_clear(DMA1, DMA_CH1, DMA_INT_FLAG_FTF); } } int main(void) { /* Initialize GPIO, TIMER and DMA */ gpio_init(); timer_init(); dma_init(); /* Enable DMA channel 1 interrupt */ eclic_irq_enable(DMA1_Channel1_IRQn, 1, 0); while (1) { /* Wait for DMA transfer complete */ while (!g_dma_transfer_complete); /* Reset DMA transfer complete flag */ g_dma_transfer_complete = 0; /* Process data */ for (int i = 0; i < BUFFER_SIZE; i++) { if (g_data_buffer[i] & GPIO_PIN_13) { /* GPIO pin 13 is high */ } else { /* GPIO pin 13 is low */ } } } } ``` 注意,在使用 DMA 读取 GPIO数据时,需要将 GPIO 口的地址作为 DMA 的外设地址。这里使用 `GPIO_BOP(GPIOB)` 获取 GPIOB 的输出寄存器地址。另外,DMA 传输完成后需要清除 DMA 传输完成标志,并在 DMA 中断中设置传输完成标志。在主函数中等待传输完成标志,然后处理数据即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大智兄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值