STM32学习日记1

您所在的位置:网站首页 stm32读取引脚电平 STM32学习日记1

STM32学习日记1

2024-06-13 16:47| 来源: 网络整理| 查看: 265

文章目录 前言一、光敏传感器引脚二、光敏传感器小实验11·读取DO引脚的高低电平来控制一个led的亮灭。2·这里提一下GPIO的工作模式3·这里提一下GPIO的输出速度 三、光敏传感器小实验21·光敏传感器DO的高低电平变化来切换OLED的显示。 四、光敏传感器小实验31·串口打印出 .光敏AO模拟输出 .经过32的ADC1 通道0 显示光强数据。 五、光敏传感器小实验41· 在小实验4的基础上,用OLED显示ADC采集的数据

前言

这是我学习32的心理路程 我会尽量把内容写的仔细 对于一些简单模块的使用,我不打算深究其原理,我只要会用它就欧克。所以看见我的32博客的同志们请注意这一点。如果同志您觉得内容有改进的地方,那就请多多指教啦~~~本人一定认真听取。

一、光敏传感器引脚

我这里使用的光敏传感器是4针的。

AO模拟输出:光敏传感器将采集的光线变成一个连续的模拟信号从AO引脚输出DO数字输出:大于光线阈值,DO引脚输出1(高电平);反之输出0。关于光线阈值,应该是调节模块上面那个十字架旋钮GND接地VCC3·3v或者5v

注意:这是我第一次使用这个模块,所以语言描述可能有bug。

3针的光敏传感器就好像没有DO引脚。其他的是一样的。

二、光敏传感器小实验1 1·读取DO引脚的高低电平来控制一个led的亮灭。

这个小实验很简单哈。

lightsensor.c

#include "stm32f10x.h" // Device header #define LED_OFF() GPIO_SetBits(GPIOB, GPIO_Pin_1 ) #define LED_NO() GPIO_ResetBits(GPIOB, GPIO_Pin_1 ) /** * @brief 光敏传感器DO引脚所连接32的PC14引脚的初始化, PC14设置为输入模式,读取DO传过来的电平。 * @param 无 * @retval 无 */ void Light_Sensor_GPIOinit(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); GPIO_InitTypeDef Light_Sensor_GPIO_InitStruct; Light_Sensor_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU ; Light_Sensor_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_14; Light_Sensor_GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC,&Light_Sensor_GPIO_InitStruct); } /** * @brief 光敏传感器所控制的led的初始化,这里我是自己外接的led * @param 无 * @retval 无 */ void Test_Sensor_LEDinit(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitTypeDef Test_Sensor_LEDinit; Test_Sensor_LEDinit.GPIO_Mode = GPIO_Mode_Out_PP ; Test_Sensor_LEDinit.GPIO_Pin = GPIO_Pin_1; Test_Sensor_LEDinit.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOB,&Test_Sensor_LEDinit); LED_OFF(); //high--->led off } /** * @brief 功能函数,读取DO电平,来控制外接LED * @param * @retval */ void Sensor_Contral_LED(void) { //uint8_t value = 0; if( GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_14) == 0 ) { LED_OFF(); } else LED_NO(); }

main.c

#include "stm32f10x.h" // Device header #include "lightsensor.h" int main (void) { Light_Sensor_GPIOinit(); Test_Sensor_LEDinit(); while(1) { //GPIO_ResetBits(GPIOB, GPIO_Pin_1 );// 测试外接led单独能不能亮 Sensor_Contral_LED(); } }

注意:lightsensor.h就是将lightsensor.c中的函数名复制一下就欧克了,这里就不多展示 了哈!

对于这个实验的总结: 开始测试外接led能不能单独亮的时候,led死活不亮,我还以为是引脚复用的毛病,但是我差了一下资料发现并不是这个问题,结果回去仔细看了一下引脚初始化才发现led要推挽输出(),以及引脚初始化结构体的问题。我麻了。后来修正后就成功点亮了,虽然这个问题是小小的不起眼的问题,至少还是需要总结一下,避免以后再犯~~~

2·这里提一下GPIO的工作模式

4种输出模式: (1)推挽输出:使用推挽输出目的是增大电流,即提高输出引脚的驱动能力,提高电路负载能力。【驱动led】

(2)开漏输出:由于只有下拉MOS管没有上拉MOS管,所以开漏输出模式下,IO引脚只能输出低电平。如果要输出高电平,则需要外接上拉电阻。

(3)复用推挽,复用开漏输出:IO引脚做复用功能时,可以选则复用推挽或者复用开漏输出模式,在选择复用开漏输出模式时,需要外接上拉电阻。

4种输入模式: (1)上拉输入模式:引脚内部有一个上拉电阻,通过开关连接到电源VDD,当IO引脚无输入信号时,默认输入高电平。【外接按键】

(2)下拉输入模式:与上拉输入模式相反。当IO引脚无输入信号时,默认输入低电平。

(3)浮空输入:引脚内部即不接上拉也不接下拉电阻。浮空输入模式下的引脚电平是不确定的,外部信号是上面电平,MCU引脚就输入什么电平。【USART,IIC等通信协议】

(4)模拟输入模式:引脚内部即不接上拉也不接下拉电阻。【A/D模拟输入实现对外部信号的采集】

3·这里提一下GPIO的输出速度

(1)输出速度并不是输出信号的的速度,而是IO口驱动电路的响应速度。“我简称为:反应能力”。

(2)32 的输出速度有3种: 2MHz, 10MHz, 50MHz,对应的就是低速反应能力,中速反应能力,高速反应能力。

当输出配置为高速时,噪声大,功耗高,电磁干扰强;当输出为低速时,噪声小,功耗低,电磁干扰弱。当输出较高频率的信号时,应该选用较高频率响应速度的驱动模块,否则容易出现信号失真现象。 一般常用的外设(例如led,蜂鸣器等)建议采用2MHz的输出速度,而作为IIC,SPI等复用功能的输出引脚时,尽量选择高响应速度,如10mhz,50hmz。 GPIO引脚做输入模式时,不需要配置引脚的输出速度。

三、光敏传感器小实验2

稍微提升一下小实验1的难度。

1·光敏传感器DO的高低电平变化来切换OLED的显示。

这里我就不贴OLED的代码了哈。

这个实验就是在实验1的lightsensor.c中加一个函数就行。

void SensorContral_LED_OLED(void) { //uint8_t value = 0; if( GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_14) == 0 ) { LED_OFF(); OLED_Clear(); OLED_ShowString(2,2,"light hight"); } else { LED_NO(); OLED_Clear(); OLED_ShowString(2,2,"light low"); } }

main.c

int main (void) { Light_Sensor_GPIOinit(); Test_Sensor_LEDinit(); OLED_Init(); while(1) { SensorContral_LED_OLED(); } }

实验总结:这个实验和实验1其实本质上上没有什么大差别,只是将led换成了OLED而已,我就想着慢慢来使用OLED屏幕,后面会慢慢提升到32用ADC采样采取光敏传感器的AO的模拟输出信号,用OLED来显示更加精确的亮度值。 对于实验2 ,我遇到一个问题:OLED出现闪屏现象。我猜测应该是主函数中的while(1)在一直循环SensorContral_LED_OLED这个函数,这个函数内部对OLED进行了清屏操作,所以就出现了闪屏现象。现在正在解决,若是解决了就放修正后代码。

修正代码的思路:(1)由于我们OLED 是静态显示,所以就不需要清屏刷新.因为在光敏传感器里面如果调用OLED的清屏函数,加上主函数while循环里面调用这个功能函数,就相当于while循环会一直有OLED清屏,所以会出现闪屏现象。(2)light hight 与 light low 长度不一样,在显示的时候会出现light lowht , 所以在light low 后面补充两个空格符,方便静态显示的时候不会出现交叠。

这刚好是OLED的静态显示所以不需要清屏刷新,但是遇到动态实时显示,需要清屏刷新怎么办捏????不需要

四、光敏传感器小实验3 1·串口打印出 .光敏AO模拟输出 .经过32的ADC1 通道0 显示光强数据。

接线:光敏的AO接32的PA0(PA0是ADC1通道0,所以已经在adc模块里面初始化了,不需要再初始化) . 在这里插入图片描述

在这里插入图片描述 上面函数:获取串口状态标志。其中第二个传参就是下面这张图。 在这里插入图片描述

无法打开串口的情况:串口调试助手没有关闭,导致串口被占用,烧录不了。 在这里插入图片描述

STM32F103C8T6 的引脚资源表。 在这里插入图片描述 myusart.c

#include "myusart.h" void MyUsart_init(void) { GPIO_InitTypeDef MyUsart_GPIO_InitStruct ; USART_InitTypeDef MyUSART_InitStruct; // 这两个结构体的定义一定要放在时钟的之前,否者编译器警告 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 ,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA,ENABLE); // usart1 Tx PA9 MyUsart_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP ; MyUsart_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; MyUsart_GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, & MyUsart_GPIO_InitStruct); //usart1 Rx PA10 MyUsart_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING ; MyUsart_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; GPIO_Init(GPIOA, & MyUsart_GPIO_InitStruct); // 初始化串口2 MyUSART_InitStruct.USART_BaudRate = 115200 ;// 波特率 MyUSART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制 MyUSART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;// 收和发模式 MyUSART_InitStruct.USART_Parity = USART_Parity_No;// 无奇偶校验位 MyUSART_InitStruct.USART_StopBits = USART_StopBits_1;// 一位停止位 MyUSART_InitStruct.USART_WordLength = USART_WordLength_8b;// 字长为8位的数据模式 USART_Init(USART1, &MyUSART_InitStruct); USART_Cmd(USART1, ENABLE);// 使能串口2 } // 发送一个字符 void Usart_send_byte(USART_TypeDef* USARTx,uint16_t Data) { USART_SendData(USARTx,Data); while( USART_GetFlagStatus(USARTx,USART_FLAG_TXE) == RESET ); } // 发送字符串,遇到字符串结尾标志‘\0’结束 void Usart_send_string(USART_TypeDef* USARTx,char *arr) { uint16_t i = 0; do { Usart_send_byte(USARTx,*(arr + i)); i++; }while(*(arr + i) != '\0'); while( USART_GetFlagStatus(USARTx,USART_FLAG_TC) == RESET ); } //重定向 printf int fputc(int ch,FILE *f) { USART_SendData(USART1,(uint8_t)ch); while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET); return (ch); } //重定向 输入 int fgetc(FILE *f) { while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) == RESET); return (int)USART_ReceiveData(USART1); }

adc.c

#include "stm32f10x.h" // Device header void ADC_init(void) { GPIO_InitTypeDef ADC_GPIO_InitStructure; ADC_InitTypeDef ADC_InitStruct;// 结构体的定义需要先于RCC的开启,否者报警告 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO ,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); // 由于ADC的最大时钟不超过14MHz,所以需要把时钟降下来。 // ADC时钟分频器;六分频;时钟从APB2总线来,最大为72MHz,所以需要六分频后12MHz。 RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 使用的是 ADC1 初始化 PA0 用于采集光敏传感器的模拟输出 ADC_GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;// 模拟输入 ADC_GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 由于是输入模式,所以不需要配置Speed. GPIO_Init(GPIOA,&ADC_GPIO_InitStructure); // 初始化ADC1 ADC_InitStruct.ADC_ScanConvMode = DISABLE;//扫描多通道还是单通道?单通道。 ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;// 连续转换还是单次转换?连续。 ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;// 数据对齐方式。右对齐。 ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//定义用于启动模拟的外部触发器到常规频道的数字转换。 ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;//将ADC配置为独立还是多模? ADC_InitStruct.ADC_NbrOfChannel = 1;//通道数量 ADC_Init(ADC1, &ADC_InitStruct); // ADC规则组配置 ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5); // ADC1,通道0,需要转换数是1,采样周期是55.5。 ADC_Cmd(ADC1,ENABLE); ADC_ResetCalibration(ADC1);//对ADC进行复位 while(ADC_GetResetCalibrationStatus(ADC1));//等待ADC复位完成 ADC_StartCalibration(ADC1);//校验ADC while(ADC_GetCalibrationStatus(ADC1));//等待ADC校验完成 ADC_SoftwareStartConvCmd(ADC1,ENABLE);//开启ADC的软件触发 } float ADC_GetValue(void) { uint32_t Value = 0; float ret = 0.0; for(uint8_t i = 0;i Light_Sensor_GPIOinit(); MyUsart_init(); ADC_init(); while(1) { printf("ADC = %.3f \n",ADC_GetValue()); Delay_ms(500); } } 这里延时半秒是:避免串口调试助手疯狂答应导致卡死。

实验现象: 在这里插入图片描述

五、光敏传感器小实验4 1· 在小实验4的基础上,用OLED显示ADC采集的数据

因为ADC采集的数据会出现小数点,所以我需要一个可以显示浮点型数据的OLED功能函数。 代码如下: OLED.c :部分代码

/** * @brief OLED显示一个字符 * @param Line 行位置,范围:1~4 * @param Column 列位置,范围:1~16 * @param Char 要显示的一个字符,范围:ASCII可见字符 * @retval 无 */ void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char) { uint8_t i; OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8); //设置光标位置在上半部分 for (i = 0; i OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]); //显示下半部分内容 } } //OLED 显示浮点型数据 // Line : 第几行 // Colum: 第几列 // Number:需要显示的浮点数(需要把浮点数据扩大为它的整型) void OLED_FloatNum1(uint8_t Line, uint8_t Column, uint32_t Number) { OLED_ShowChar(Line,Column + 0,(Number/10000) + '0');// 最高位 OLED_ShowChar(Line,Column + 1,(Number/1000%10) + '0'); OLED_ShowChar(Line,Column + 2,'.');// 固定显示 OLED_ShowChar(Line,Column + 3,(Number/100%10) + '0'); OLED_ShowChar(Line,Column + 4,(Number/10%10) + '0'); OLED_ShowChar(Line,Column + 5,(Number%10) + '0'); }

就是用这两个函数来显示浮点型数据。

ADC.c:采样功能代码,实验3这个部分和这里大致没有差别,这个代针对OLED,所以返回值会有一个小小的处理。

float ADC_GetValue(void) { uint32_t Value = 0; float ret = 0.0; for(uint8_t i = 0;i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3