61

帖子

0

TA的资源

一粒金砂(中级)

21
 
tagetage 发表于 2024-12-23 12:25 按理说没有上升沿或者下降沿它是不会有中断的。-------是的,但是我上面也说了,,在软件里判断,有中断则 ...

了解啦!非常感谢

此帖出自stm32/stm8论坛
 

回复

61

帖子

0

TA的资源

一粒金砂(中级)

22
 
tagetage 发表于 2024-12-23 12:16 IO轮询的话,我考虑的是:一直轮询监测是否是高电平的话,风扇正常运转的话,可能也会刚好多次轮循到高电 ...

是的,刚接触编程没多久!所以需要多请教!我先尝试看看中断能不能搞定,如果实在不行,就按照您说的这样去轮询

此帖出自stm32/stm8论坛
 
 

回复

61

帖子

0

TA的资源

一粒金砂(中级)

23
 
tagetage 发表于 2024-12-23 11:45 很高兴你采纳了我的建议并取得了很好的效果。 来进行监测stm32的IO口是否一直处于高电平啊?----用软 ...

上午好,冒昧打扰到您了!还是上次那个问题,我采用stm32的一个输入捕获通道通过您推荐的SN74HC251芯片来读取风扇转速,现在遇到一个问题,搞了两天一直不知道哪里出了问题?

现象是这样的:

1、我现在用一颗SN74HC251去控制了六个风扇分别采用输入捕获通道读取转速,然后转速获取到之后,在OLED上面进行转速显示,我总共连接了五个风扇,其中第二个风扇我拔掉了,没链接,验证风扇出故障情况下是否会显示0转速。

其中理论转速:第一个风扇转速应该是:3600转,第二个拔掉了应该是:0转,第三个应该是3600转,第四个、第五个、第六个应该是:2400转

但是实际显示出来的结果是:第一个风扇转速是:2400转,第二个拔掉了是:0转,第三个是3600转,第四个是:3600转,第五个、第六个是:2400转

经过查看发现,显示错位了。我感觉是输入捕获捕获的还是上一次的值。

2、于是我采用单步调试进行验证看是否数据错位,但是神奇的是我单步调试的时候,显示完全OK,没有错位,我不断更改代码,但是就是解决不了问题,于是实在是没招,只能跟您请教下,实在是不好意思打扰到您了。

代码如下:

SN74HC251控制程序:

#include "stm32f10x.h"                  // Device header

//IO定义
#define GPIO_Clk_A RCC_APB2Periph_GPIOA
#define GPIO_Port_EN GPIOA
#define GPIO_Pin_EN GPIO_Pin_4

#define GPIO_Pin_A GPIO_Pin_0
#define GPIO_Pin_B GPIO_Pin_1
#define GPIO_Pin_C GPIO_Pin_2

/**
  * 函    数:HC251多路复用器引脚初始化
  * 参    数:无
  * 返 回 值:无
  */
void HC251_Init (void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(GPIO_Clk_A, ENABLE);				//开启GPIOB的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;					//定义结构体变量
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		//GPIO模式,赋值为推挽输出模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_A | GPIO_Pin_B | GPIO_Pin_C | GPIO_Pin_EN;	//GPIO引脚,赋值为第12、13、14、15号引脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		//GPIO速度,赋值为50MHz
	
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//将赋值后的构体变量传递给GPIO_Init函数
															//函数内部会自动根据结构体的参数配置相应寄存器
															//实现GPIOB的初始化
}

/**
  * 函    数:HC251多路复用器失能
  * 参    数:无
  * 返 回 值:无
  */
void HC251_Disable(void)
{
    GPIO_SetBits(GPIO_Port_EN, GPIO_Pin_EN);
}

/**
  * 函    数:HC251多路复用器使能
  * 参    数:无
  * 返 回 值:无
  */
void HC251_Enable(void)
{
    GPIO_ResetBits(GPIO_Port_EN, GPIO_Pin_EN);
}

/**
  * 函    数:HC251多路复用器通道选择
  * 参    数:Channel 通道 范围:0 ~ 7
  * 返 回 值:无
  */
void HC251_SetChannel(uint8_t Channel)
{
    switch (Channel)
    {
    case 0:
        GPIO_ResetBits(GPIOA, GPIO_Pin_A);
        GPIO_ResetBits(GPIOA, GPIO_Pin_B);
        GPIO_ResetBits(GPIOA, GPIO_Pin_C);
        break;
    case 1:
        GPIO_SetBits(GPIOA, GPIO_Pin_A);
        GPIO_ResetBits(GPIOA, GPIO_Pin_B);
        GPIO_ResetBits(GPIOA, GPIO_Pin_C);
        break;
    case 2:
        GPIO_ResetBits(GPIOA, GPIO_Pin_A);
        GPIO_SetBits(GPIOA, GPIO_Pin_B);
        GPIO_ResetBits(GPIOA, GPIO_Pin_C);
        break;
    case 3:
        GPIO_SetBits(GPIOA, GPIO_Pin_A);
        GPIO_SetBits(GPIOA, GPIO_Pin_B);
        GPIO_ResetBits(GPIOA, GPIO_Pin_C);
        break;
    case 4:
        GPIO_ResetBits(GPIOA, GPIO_Pin_A);
        GPIO_ResetBits(GPIOA, GPIO_Pin_B);
        GPIO_SetBits(GPIOA, GPIO_Pin_C);
        break;
    case 5:
        GPIO_SetBits(GPIOA, GPIO_Pin_A);
        GPIO_ResetBits(GPIOA, GPIO_Pin_B);
        GPIO_SetBits(GPIOA, GPIO_Pin_C);
        break;
    case 6:
        GPIO_ResetBits(GPIOA, GPIO_Pin_A);
        GPIO_SetBits(GPIOA, GPIO_Pin_B);
        GPIO_SetBits(GPIOA, GPIO_Pin_C);
        break;
    case 7:
        GPIO_SetBits(GPIOA, GPIO_Pin_A);
        GPIO_SetBits(GPIOA, GPIO_Pin_B);
        GPIO_SetBits(GPIOA, GPIO_Pin_C);
        break;
    }
}

风扇是否停转、堵转监测程序:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

uint8_t Data[4] = {0};					//FG信号输入IO口电平状态数组
uint8_t IOState_Flag = 0;

/**
  * 函    数:计数传感器初始化
  * 参    数:无
  * 返 回 值:无
  */
void IO_State_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);						//将PB0引脚初始化为上拉输入
}

/**
  * 函    数:获取状态标志位
  * 参    数:无
  * 返 回 值:IOState_Flag 取值:0/1
  */
uint8_t IO_GetState(void)
{
	uint8_t i = 0;
	for(i=0; i<4; i++)//扫描4个通道是否为0
	{
		Data[i] = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0);
		Delay_ms(4);
	}
	if (Data[0]==Data[1] && Data[1]==Data[2] && Data[2]==Data[3])			//如果均为0
	{
		IOState_Flag = 1;	//则返回1
	}
	else
	{
		IOState_Flag = 0;	//则返回0
	}
	return IOState_Flag;	
}

输入捕获获取转速值程序:

#include "stm32f10x.h"                  // Device header
#include "RpmGet_Delay.h"
#include "IO_State.h"
#include "HC251.h"

uint16_t Rpm[6] = {0};					//定义转速数组
uint8_t i = 0;

/**
  * 函    数:输入捕获初始化
  * 参    数:无
  * 返 回 值:无
  */
void IC_Init(void)
{
	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);			//开启TIM3的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);							//将PA6引脚初始化为上拉输入
	
	/*配置时钟源*/
	TIM_InternalClockConfig(TIM3);		//选择TIM3为内部时钟,若不调用此函数,TIM默认也为内部时钟
	
	/*时基单元初始化*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;               //计数周期,即ARR的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;               //预分频器,即PSC的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置TIM3的时基单元
	
	/*输入捕获初始化*/
	TIM_ICInitTypeDef TIM_ICInitStructure;							//定义结构体变量
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;				//选择配置定时器通道1
	TIM_ICInitStructure.TIM_ICFilter = 0xF;							//输入滤波器参数,可以过滤信号抖动
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;		//极性,选择为上升沿触发捕获
	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;			//捕获预分频,选择不分频,每次信号都触发捕获
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;	//输入信号交叉,选择直通,不交叉
	TIM_ICInit(TIM3, &TIM_ICInitStructure);							//将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道
	
	/*选择触发源及从模式*/
	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);					//触发源选择TI1FP1
	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);					//从模式选择复位
																	//即TI1产生上升沿时,会触发CNT归零
	
	/*TIM使能*/
	TIM_Cmd(TIM3, ENABLE);			//使能TIM3,定时器开始运行
}

/**
  * 函    数:转速获取初始化
  * 参    数:无
  * 返 回 值:无
  */
void RpmGet_Init(void)
{
	Timer7_Init();
	IC_Init();
	HC251_Init();					//风扇转速捕获初始化
	IO_State_Init();
}

/**
  * 函    数:获取风扇的实际转速
  * 参    数:无
  * 返 回 值:无
  */
void RpmGet_Value(void)
{
	//Flag是标志位,是通过TIM7定时器中断产生的,定时器1ms产生依次中断,然后设置计数值为1000
	//1000减至0,将Flag置1,通过这种方式达到1秒换一个通道捕获一次转速
	if(Flag == 1 && i<6)
	{
		HC251_Disable();
		HC251_SetChannel(i);
		HC251_Enable();								//这里我也尝试加了延时,最多5ms,但是没用
		
		//输入捕获获取到的值经过公式转换为转速值,再赋值给数Rpm数组
		Rpm[i] = 30 * (1000000 / (TIM_GetCapture1(TIM3) + 1));
		
		if(IO_GetState() == 1)				//该代码是监测风扇是否堵转,停转
		{
			Rpm[i] = 0;
		}					
		i++;
		Flag = 0;
		if(i == 6)
		{
			i = 0;
		}
	}
}

主程序如下:

#include "stm32f10x.h"                  // Device header
#include "PowerSupply_Control.h"
#include "MyDelay.h"
#include "IO_State.h"
#include "Delay.h"
#include "PWM.h"
#include "OLED.h"
#include "Key.h"
#include "Timer.h"
#include "AD.h"
#include "RpmGet.h"
#include "NTC.h"

uint8_t KeyNum;		//定义用于接收按键码的变量
uint16_t SpeedA,SpeedB;		//定义速度变量
//float A0, A1;	//定义AD值变量

int main(void)
{
	/*模块初始化*/
	OLED_Init();					//OLED初始化
	PWM_Init();						//PWM初始化
	Key_Init();						//按键初始化
	PowerSupply_Control_Init();		//供电IO口初始化
	Timer_Init();					//定时器初始化
	RpmGet_Init();	
	
	/*显示静态字符串*/
	OLED_ShowString(1,1,"SD:000&000&000");		//1行1列显示字符串Speed:
	OLED_ShowString(2,1,"A:0000&0000&0000");	//2行1列显示字符串RpmA:
	OLED_ShowString(3,1,"B:0000&0000&0000");	//2行1列显示字符串RpmB:
	OLED_ShowString(4,1,"C:0000&0000&0000");	//2行1列显示字符串RpmC:
//	OLED_ShowString(2, 10, "A0:00.0");
//	OLED_ShowString(3, 10, "A1:00.0");
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	//NVIC中断分组
	
	while(1)
	{
		OLED_ShowNum(3,13,IO_GetState(),2);		
		KeyNum = Key_GetNum();			//获取按键键码
		if(KeyNum == 2)					//按键1按下
		{
			SpeedA += 20;				//速度变量自增20
			SpeedB += 20;

			if(SpeedA > 100)				//速度变量超过100后
			{
				SpeedA = 0;				//速度变量变为0
			}
			if(SpeedB > 100)				//速度变量超过100后
			{
				SpeedB = 0;				//速度变量变为0
			}
		}
		PWM_SetCompare1(SpeedA);			//设置直流风扇的速度为速度变量
		PWM_SetCompare2(SpeedB);	
		OLED_ShowNum(1,4,SpeedA,3);		//OLED显示速度变量
		OLED_ShowNum(1,8,SpeedB,3);
		
		if(Capture_Flag[3] == 1)		//标志位置1,代表一次延时完成
		{
			PowerSupply_Control_NG();	//风扇供电电压翻转
			Capture_Flag[3] = 0;		//标志位置0
		}
		
		RpmGet_Value();		
		OLED_ShowNum(2,3,Rpm[0],4);		//2行3列显示第一个风扇实际转速	
		OLED_ShowNum(2,8,Rpm[1],4);		//2行8列显示第二个风扇实际转速	
		OLED_ShowNum(3,3,Rpm[2],4);		//3行3列显示第三个风扇实际转速	
		OLED_ShowNum(3,8,Rpm[3],4);		//3行8列显示第四个风扇实际转速	
		OLED_ShowNum(4,3,Rpm[4],4);		//4行3列显示第五个风扇实际转速	
		OLED_ShowNum(4,8,Rpm[5],4);		//4行8列显示第六个风扇实际转速		

//		A0 = read_battery_ntc(AD_Value[0]); 
//		A1 = read_battery_ntc(AD_Value[1]);				
//		OLED_ShowNum(2, 13, (uint16_t)A0, 2);		//显示转换结果第0个数据
//		OLED_ShowNum(2, 16, (uint16_t)(A0 * 10) %10, 1);		//显示转换结果第1个数据
//		OLED_ShowNum(3, 13, (uint16_t)A1, 2);		//显示转换结果第0个数据
//		OLED_ShowNum(3, 16, (uint16_t)(A1 * 10) %10, 1);		//显示转换结果第1个数据
//		
//		Delay_ms(100);			//延时100ms,手动增加一些转换的间隔时间
	}
}

还请劳烦您费心看下,不甚感激!

此帖出自stm32/stm8论坛
 
 

回复

61

帖子

0

TA的资源

一粒金砂(中级)

24
 
tagetage 发表于 2024-12-23 11:45 很高兴你采纳了我的建议并取得了很好的效果。 来进行监测stm32的IO口是否一直处于高电平啊?----用软 ...

对了,stm32芯片采用的是:STM32F103RCT6

此帖出自stm32/stm8论坛
 
 
 

回复

3206

帖子

0

TA的资源

五彩晶圆(中级)

25
 

我不断更改代码,但是就是解决不了问题,于是实在是没招,只能跟您请教下,实在是不好意思打扰到您了。代码如下:--------------有问题没有什么打扰的,我都会在论坛里尽量回复。我好久不做具体得编程了,要是在公司的话像这样编程的活儿都手下的干,你贴的代码我也没办法看,但我会告诉你怎么调试。

你这个项目就是采集六个风扇转速,然在OLED上显示,你描述的问题应该是软件方面的问题。

如果这个项目我手下干的话我会这么建议编程顺序。

1,采集风扇转速。

2,OLED驱动。

3,一个风扇的采集和OLED显示。

4,多个风扇的采集和OLED显示。

你现在问题应该是在3,一个风扇的采集和OLED显示。 这个步骤没有做好。

我建议你编程做法是,先把一个风扇的转速显示给做好了。包括最低转 最高转 和没有连接风扇状态和转数变化状态。

一个风扇转速显示给做好了,同理做6路也就不难了。。

此帖出自stm32/stm8论坛

点评

我是按照这个流程去弄的,先调试的一个风扇,后面才慢慢增加风扇的,其实不增加风扇,只要将其余监测通道打开,我就发现数据就会不准,总感觉输入捕获回来的值就会偶尔出现错误!我输入捕获采用的主从模式,总感觉是  详情 回复 发表于 2025-1-3 11:30
 
 
 

回复

3206

帖子

0

TA的资源

五彩晶圆(中级)

26
 

调试的话可以用另外一套系统来做风扇的转数设置,比如PWM信号发生器什么的,另一套系统把风扇转速调到1000,你的OLED马上就能显示1000,另一套系统把风扇转速调到2000,你的OLED马上就能显示2000,要是拔掉风扇或停转就显示0,做到这样才可以。

此帖出自stm32/stm8论坛
 
 
 

回复

61

帖子

0

TA的资源

一粒金砂(中级)

27
 
tagetage 发表于 2025-1-3 10:27 我不断更改代码,但是就是解决不了问题,于是实在是没招,只能跟您请教下,实在是不好意思打扰到您了。代码 ...

我是按照这个流程去弄的,先调试的一个风扇,后面才慢慢增加风扇的,其实不增加风扇,只要将其余监测通道打开,我就发现数据就会不准,总感觉输入捕获回来的值就会偶尔出现错误!我输入捕获采用的主从模式,总感觉是捕获时CCR寄存器的值不是当前风扇的转速,之前三个风扇一起测试时,我都是转速一样测试的,现在我将有的风扇转速快,有的风扇转速慢,现在问题就出来了

此帖出自stm32/stm8论坛
 
 
 

回复

3206

帖子

0

TA的资源

五彩晶圆(中级)

28
 

只要将其余监测通道打开,我就发现数据就会不准,总感觉输入捕获回来的值就会偶尔出现错误-------问题出现在切换上,那我猜你 通道切换时候你要关闭采集,切换后在打开采集,要不然通道切换不也算是PWM波形里面了嘛。。

此帖出自stm32/stm8论坛
 
 
 

回复

3206

帖子

0

TA的资源

五彩晶圆(中级)

29
 

还有采集的数据要延时采集,比如切换通道后,等波形稳定了在采集,或采集3组数据做比较然后处理。

此帖出自stm32/stm8论坛
 
 
 

回复

3206

帖子

0

TA的资源

五彩晶圆(中级)

30
 

以上都是编程的细节问题,你应该多想一想,这个项目软硬件的总体架构我认为都没有问题,剩下的就是细节了。

此帖出自stm32/stm8论坛

点评

非常感谢大佬您的耐心指导,前段时间忙别的去了,这两天花时间按照您指导的方式,由简单入手,先搞定一个风扇的各种情况,然后再慢慢增加风扇,优化了代码,特别是您提到的切换通道时要关闭采集,同时也需要足够的延  详情 回复 发表于 2025-1-13 16:21
 
 
 

回复

61

帖子

0

TA的资源

一粒金砂(中级)

31
 
tagetage 发表于 2025-1-3 12:31 以上都是编程的细节问题,你应该多想一想,这个项目软硬件的总体架构我认为都没有问题,剩下的就是细节了。 ...

非常感谢大佬您的耐心指导,前段时间忙别的去了,这两天花时间按照您指导的方式,由简单入手,先搞定一个风扇的各种情况,然后再慢慢增加风扇,优化了代码,特别是您提到的切换通道时要关闭采集,同时也需要足够的延时,这个问题终于解决了!真的是太感激了,编程还有很多细节需要跟大佬们多多学习!万分感激

此帖出自stm32/stm8论坛

点评

你这个项目完成了我也很高兴,主要是你听“劝”,最怕干了3,5年的工程师水平一般还“犟”,我说的增加74HC251和软件方面的重点细节,还有编程流程你能采纳说明你还是非常有判断能力的。你以后  详情 回复 发表于 2025-1-13 17:09
 
 
 

回复

3206

帖子

0

TA的资源

五彩晶圆(中级)

32
 
Tacking 发表于 2025-1-13 16:21 非常感谢大佬您的耐心指导,前段时间忙别的去了,这两天花时间按照您指导的方式,由简单入手,先搞定一个 ...

你这个项目完成了我也很高兴,主要是你听“劝”,最怕干了3,5年的工程师水平一般还“犟”,我说的增加74HC251和软件方面的重点细节,还有编程流程你能采纳说明你还是非常有判断能力的。你以后再这个行业一定很厉害。

 

此帖出自stm32/stm8论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表