草庐IT

STM32——ADC读取光敏传感器控制LED灯,看门狗中断

chfens 2024-02-20 原文

本文介绍两种使用方法

一、编写读取AD值的函数,之后判断AD值,进行相应操作,比如点灯。
二、用ADC读取光敏传感器AO口输出,并配置ADC通道看门狗监控这条通道,当光线太暗时打开LED灯。
之后会再介绍可编程RGB灯带WS2812B。

光敏传感器介绍

光敏传感器有两个输出口,一个是DO(Digital Output),一个是AO(Analog Output),DO是数字输出,只会输出0或1,AO是模拟输出,可以配合stm32的ADC转换器得到数值存放在12位的寄存器中,因此AD值的范围是4095 - 0,即2的12次方-1到2的0次方。

程序代码

#include "LightAD.h"
#include "stm32f10x.h"                  // Device header
#include "LED.h"

#define RCC_LightADC RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA

#define GPIO_LightADC GPIOA
#define PIN_LightADC GPIO_Pin_0
#define Channel_LightADC ADC_Channel_0

unsigned int HighThreshold = 3000;
unsigned int LowThreshold = 0;

//用AD转换配合模拟看门狗 单次转换非扫描

extern char BrightEnough; 

先宏定义引脚和通道,定义三个变量,两个是看门狗监控的高低阈值,一个是main.c中定义的标志位,判断当前光线是否够亮。

void Light_GPIOInit()
{
	GPIO_InitTypeDef GPIO_AD;
	GPIO_AD.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_AD.GPIO_Pin =  PIN_LightADC;		
	GPIO_AD.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIO_LightADC,&GPIO_AD);	
}

配置GPIO口,注意GPIO模式要选择模拟输入

void WatchDog_ADInit()
{
	ADC_AnalogWatchdogSingleChannelConfig(ADC1, Channel_LightADC);
	ADC_AnalogWatchdogThresholdsConfig(ADC1,HighThreshold,LowThreshold);
	ADC_AnalogWatchdogCmd(ADC1,ADC_AnalogWatchdog_SingleRegEnable);
	
	ADC_ITConfig(ADC1,ADC_IT_AWD,ENABLE);
}

配置看门狗,选择ADC1或2,选择对应通道,这里只有一个光敏传感器,一般选择通道0。

void Light_NVICInit()
{
	NVIC_InitTypeDef nvic_struct;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	nvic_struct.NVIC_IRQChannel = ADC1_2_IRQn;
	nvic_struct.NVIC_IRQChannelCmd = ENABLE;
	nvic_struct.NVIC_IRQChannelPreemptionPriority = 3;
	nvic_struct.NVIC_IRQChannelSubPriority = 3;
	
	NVIC_Init(&nvic_struct);
}

开启NVIC通道,优先级随便填。

void ADC1_2_IRQHandler()
{
	if(ADC_GetITStatus(ADC1,ADC_IT_AWD) == 1)
	{
		BrightEnough = 0;
		LEDOn();
		ADC_ClearITPendingBit(ADC1,ADC_IT_AWD);
	}
}

配置中断函数,当进入中断,则光线不够亮,并打开LED灯,最后清除标志位,注意中断标志位是ADC_IT_AWD。

void Light_ADInit()
{
	//ADC1通道0在PA0
	RCC_APB2PeriphClockCmd(RCC_LightADC,ENABLE);
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//最高14Mhz,72 六分频 12Mhz
	
	Light_GPIOInit();//1
	
	//选择规则组的输入通道
	//通道0,序列1,中等采样时间
	ADC_RegularChannelConfig(ADC1, Channel_LightADC, 1, ADC_SampleTime_55Cycles5);
	
	//初始化ADC
	ADC_InitTypeDef adc_struct;
	adc_struct.ADC_Mode = ADC_Mode_Independent;
	adc_struct.ADC_DataAlign = ADC_DataAlign_Right;
	adc_struct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	adc_struct.ADC_NbrOfChannel = 1;
	adc_struct.ADC_ContinuousConvMode = DISABLE;
	adc_struct.ADC_ScanConvMode = DISABLE;
	//单次转换非扫描,只有一个通道
	ADC_Init(ADC1,&adc_struct);
	
	//配置看门狗和中断
	WatchDog_ADInit();//2
	Light_NVICInit();//3
	
	ADC_Cmd(ADC1,ENABLE);
	
	//先复位校准
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1) == 1);
	//等待复位校准完成,当寄存器软件置1开始校准,校准完硬件置0
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1) == 1);
}

配置ADC,选择规则组的输入通道,选择ADC独立模式,而不是ADC1和ADC2共同工作的合作模式,后者的优势是转换更快,但是没必要,ADC转换时间是很短的,下面会有计算。设置数据对齐方式是右对齐。一般都是设置右对齐,左右对齐的知识大家可以自行搜索。选择不设置外部触发源,选择单次触发,非扫描模式。通道数量设置为1条。之后记得复位校准,否则可能造成数值漂移。

//可以采用单次扫描更改扫描通道的方式来实现多通道采集,注意修改GPIO初始化引脚
unsigned int Light_GetADVal()
{
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == 0);
	//等待规则组转换完成
	//采样时间是55.5,转换固定周期是12.5,一共68个周期
	//72MHZ6分频,12Mhz 68个周期,时间大约是1/12M * 68,约5.6us
	ADC_SoftwareStartConvCmd(ADC1,DISABLE);
	return ADC_GetConversionValue(ADC1);
}

读取AD值,AD转换周期如程序中注释所示,得出时间大约为5.6us,时间非常短。同时,如果有多个输入设备,可以采用单次非扫描的方式来达到单次连续扫描的效果,只需要在一个设备读取完之后更改下次要读取的通道,每次读取完之后更新AD数值和通道。
方法一只要在主函数中拿读取到的AD值判断后再执行功能就行,方法二用上面的看门狗代码配置后在看门狗中断中配置函数即可。

结语

STM32的ADC功能很多,这里只是简单介绍基本使用的方法,剩下内容留待读者去探索。

有关STM32——ADC读取光敏传感器控制LED灯,看门狗中断的更多相关文章

  1. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  2. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  3. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  4. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

  5. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  6. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

    说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

  7. ruby - 是否可以在不实际发送或读取数据的情况下查明 ruby​​ 套接字是否处于 ESTABLISHED 或 CLOSE_WAIT 状态? - 2

    s=Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)s.connect(Socket.pack_sockaddr_in('port','hostname'))ssl=OpenSSL::SSL::SSLSocket.new(s,sslcert)ssl.connect从这里开始,如果ssl连接和底层套接字仍然是ESTABLISHED,或者它是否在默认值7200之后进入CLOSE_WAIT,我想检查一个线程几秒钟甚至更糟的是在实际上不需要.write()或.read()的情况下关闭。是用select()、IO.select()还是其他方法完成

  8. ruby - 如何从 ARGF 读取 csv - 2

    在Ruby1.9中,我如何从ARGF中读取CSV?我尝试了以下方法,但没有打印任何内容:require'csv'CSV(ARGF).readdo|row|prowendhttp://www.ruby-doc.org/core-1.9.3/ARGF.htmlhttp://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV.html 最佳答案 如果你想偷懒你可以试试:CSV.new(ARGF.file).eachdo|row|...end来源:http://www.ruby-doc.org/std

  9. Ruby:写入 stdin 并从 stdout 读取? - 2

    我正在编写一个ruby​​程序,它应该执行另一个程序,通过stdin向它传递值,从它的stdout读取响应,然后打印响应。这是我目前所拥有的。#!/usr/bin/envrubyrequire'open3'stdin,stdout,stderr=Open3.popen3('./MyProgram')stdin.puts"helloworld!"output=stdout.readerrors=stderr.readstdin.closestdout.closestderr.closeputs"Output:"puts"-------"putsoutputputs"\nErrors:"p

  10. ruby - 是否可以从 ruby​​ 脚本返回值并在 c 或 shell 脚本中读取该值? - 2

    我们如何从ruby​​脚本返回值?#!/usr/bin/envrubya="test"a我们如何在Ubuntu终端或java或c中访问'a'的值? 最佳答案 在ruby​​/python脚本中打印你的变量,然后可以通过示例从shell脚本中读取它:#!/bin/bashruby_var=$(rubymyrubyscript.rb)python_var=$(pythonmypythonscript.py)echo"$ruby_var"echo"$python_var"注意你的ruby​​/python脚本只打印这个变量(有更多复杂的方

随机推荐