
开源协议
:GPL 3.0
(未经作者授权,禁止转载)描述
功能介绍
自动模式
下大雨会打开窗帘,优先级高于光照;
光照太强,打开窗帘;光照太弱,关闭窗帘;
手动模式
通过红外遥控控制:打开窗帘;关闭窗帘;自动模式;手动模式;
通过语音命令控制:打开窗帘;关闭窗帘;自动模式;手动模式;
雨滴模块
1.实物图
2.原理
电导性雨滴传感器通常由两个电极组成,它们之间存在一定的电流。当雨滴接触到电极时,由于雨滴具有导电性,电流会通过雨滴流动,从而改变电极之间的电阻。通过测量这个电阻的变化,就可以判断是否有雨滴存在。
3.原理图
4.数据流
5.关键代码
/******************************************************************
* 函 数 名 称:get_raindrop_percentage_value
* 函 数 说 明:读取雨滴AO值,并且返回百分比
* 函 数 形 参:无
* 函 数 返 回:返回百分比
* 作 者:T
* 备 注:无
******************************************************************/
unsigned int get_raindrop_percentage_value(void)
{
int adc_max = 4095;
int adc_new = 0;
int Percentage_value = 0;
adc_new = get_adc_value( BSP_RAINDROP_ADC_CHANNEL ); //根据采集通道获取ADC值
Percentage_value = (1-((float)adc_new/adc_max)) * 100; //这里雨滴值用1-取反一下,更符合思维习惯
return Percentage_value;
}
光敏模块
1.实物图
2.原理
光敏电阻的工作原理可以简单理解为:光照强度增加,电阻值降低;光照强度减小,电阻值增加。
光敏电阻内部的光敏材料会受到光的照射,光子激发了材料中的电子,使其跃迁到高能级。这种激发导致了电阻器中电荷移动的变化,从而改变了电阻值。当光照强度较大时,更多的光子激发了电子,电荷移动增多,电阻值减小;当光照强度较小时,光子激发的电子减少,电荷移动减少,电阻值增加。
3.原理图
4.数据流
5.关键代码
/******************************************************************
* 函 数 名 称:get_light_percentage_value
* 函 数 说 明:读取光照AO值,并且返回百分比
* 函 数 形 参:无
* 函 数 返 回:返回百分比
* 作 者:LC
* 备 注:无
******************************************************************/
unsigned int get_light_percentage_value(void)
{
int adc_max = 4095;
int adc_new = 0;
int Percentage_value = 0;
adc_new = get_adc_value( BSP_LIGHT_ADC_CHANNEL ); //根据采集通道获取ADC值
Percentage_value = (1-((float)adc_new/adc_max)) * 100; //这里光照值用1-取反一下,更符合思维习惯
return Percentage_value;
}
步进电机模块
1.实物图
2.原理
步进电机
步进电机是将电脉冲信号,转变为角位移或线位移的开环控制电机,又称为脉冲电机。它的转角是离散化的,也就是说它的每一次转动是由若干个固定角度的步进构成的。可以通过很短的脉冲信号来精确控制角度和速度。
它的原理可分为两种类型:磁极式和磁阻式。在磁极式步进电机中,电机转子上的磁极会受到外部磁场的作用,从而产生转矩,使得电机转子转动。在磁阻式步进电机中,电机转子上的磁极会在磁场的作用下受到吸引力和排斥力,从而产生转矩,使得电机转子转动。无论哪一种,其控制原理都是通过依次通电于各个电极,以改变电机的磁场方向和大小来产生转矩。
一般情况下,电机的转速、停止的位置只取决于脉冲信号的频率和脉冲数。当步进驱动器接收到一个脉冲信号时,它就可以驱动步进电机按设定的方向转动一个固定的角度。因此:
- 可以通过控制脉冲个数来控制角位移量,从而达到准确定位的目的;
- 可以通过控制脉冲频率来控制电机转动的速度和加速度,从而达到调速的目的;
- 可以通过控制绕组通电顺序,达到控制电机正反转的目的。
步进电机是有定子和转子组成:
- 定子,就是由电流控制磁场方向,通电时就会产生磁力;
- 转子,被定子环绕在中间受定子磁场变化产生转动(下方示意图中转动的指针)
通过给定子通电,产生磁力,将转子吸附过来,那转子就会转一小格;通过给定子连续的通电,就可以实现让转子转动。
四相五线步进电机(28BYJ48)
四相:四个线圈;
五线:每一个线圈对应一根线,加一个公共线。其中红色是公共线,A+、A-、B+、B- 各代表一相。
28:步进电机的有效最大外径28mm;
B:步进电机的“步”字拼音首字母;
Y:永磁式“永”字拼音首字母;
J:减速型“减”字拼音首字母;
48:四相八拍
减速比:1:64
要让它转动起来,需要给线圈连续通电。而转动方式有多种,这里只介绍八拍方式,其它方式同理。
八拍方式的转动顺序:【A+】->【A+B+】->【B+】->【B+A-】->【A-】->【A-B-】->【B-】->【B-A+】:
ULN2003A
ULN2003A是单片集成高耐压、大电流达林顿管阵列,电路内部包含七路独立的达林顿管驱动电路。电路内部有续流二极管,可用于驱动继电器、步进电机等电感性负载。单路达林顿管集电极可输出 500mA 电流。
这个芯片IN和OUT是对应的,也就是说INX控制OUTX(X=1、2、3、4、5、6、7),但是控制逻辑是反的,就是说IN1是高电平,OUT1是低电平;IN1是低电平,OUT1是高电平。但是公共端接的是高电平,OUT端输出低电平的时候反而是导通的,所以对应的IN端输入的是高电平。
3.原理图
4.数据流
5.关键点
脉冲频率
给到电机的脉冲需要一定的时间间隔,如果电机还没被吸附过去,脉冲就结束的话,电机只会震动,不会旋转。本项目开启了定时器5计时中断,作为步进电机的脉冲频率,每隔 1 Ms,更新一次脉冲。
正、反转
步进电机的转动本质上就是按一定时序给几组线圈通断电
步数
反转增加步数,到最大值不再增加;正传减少步数,到最小值不再减少。这里驱动方式用8拍,减速比是1:64,且拿一圈作为电机的行程,即一圈步数应该为8*64
考虑到实际情况,这个步数应该有个初值,且要存放在ROM里面,一上电先获取电机步数,即窗帘位置。本项目V1.0版本先模拟实际情况设个初值,后续版本再优化。
电机正反转标志位
这是一种常见的“二极管”思想,它相当于对底层进行了一层封装,上层的代码只需要控制标志位就可以控制电机的正反转。
6.关键代码
/******************************************************************
* 函 数 名 称:stepper_motor_timer_config
* 函 数 说 明:步进电机脉冲更新频率定时器初始化
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:T
* 备 注:设置为1ms,即每1ms更新一次脉冲
******************************************************************/
void stepper_motor_timer_config(void)
{
/* 一个周期的时间T = 1/f, 定时时间time = T * 周期
设预分频值位pre,周期位per
time = (pre + 1) * (per + 1) / psc_clk
*/
timer_parameter_struct timere_initpara; // 定义定时器结构体
/* 开启时钟 */
rcu_periph_clock_enable(RCU_TIMER5); // 开启定时器时钟
/* CK_TIMERx = 4 x CK_APB1 = 4x50M = 200MHZ */
rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4); // 配置定时器时钟
timer_deinit(TIMER5); // 复位定时器
/* 配置定时器参数 */
timere_initpara.prescaler = 1000-1; // 时钟预分频值 0-65535
timere_initpara.alignedmode = TIMER_COUNTER_EDGE; // 边缘对齐
timere_initpara.counterdirection = TIMER_COUNTER_UP; // 向上计数
timere_initpara.period = 200-1; // 周期
timere_initpara.clockdivision = TIMER_CKDIV_DIV1; // 分频因子
timere_initpara.repetitioncounter = 0; // 重复计数器 0-255
timer_init(TIMER5,&timere_initpara); // 初始化定时器
/* 配置中断优先级 */
nvic_irq_enable(TIMER5_DAC_IRQn,3,2); // 设置中断优先级为 3,2
/* 使能中断 */
timer_interrupt_enable(TIMER5,TIMER_INT_UP); // 使能更新事件中断
/* 使能定时器 */
timer_enable(TIMER5);
}
/************************************************
函数名称 : BSP_TIMER_IRQHandler
功 能 : 基本定时器中断服务函数
参 数 : 无
返 回 值 : 无
作 者 : T
备 注 : 无
*************************************************/
void TIMER5_DAC_IRQHandler(void)
{
/* 这里是定时器中断 */
if(timer_interrupt_flag_get(TIMER5,TIMER_INT_FLAG_UP) == SET)
{
timer_interrupt_flag_clear(TIMER5,TIMER_INT_FLAG_UP); // 清除中断标志位
//顺时针旋转
step_motor45_cw();
//逆时针旋转
step_motor45_ccw();
}
}
/******************************************************************
* 函 数 名 称:step_motor45_cw
* 函 数 说 明:四相五线步进电机顺时针转动
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:T
* 备 注:顺时针,转动顺序:a+ b+ a- b-
******************************************************************/
void step_motor45_cw(void)
{
static uint8_t i=0;
//开启了顺时针动作
if( motor_cw_flag == 1 )
{
AP ( ( phasecw[i] >> 3 ) & 0x01 );
BP ( ( phasecw[i] >> 2 ) & 0x01 );
AM ( ( phasecw[i] >> 1 ) & 0x01 );
BM ( ( phasecw[i] >> 0 ) & 0x01 );
//拍数增加
i = ( i + 1 ) % 8; //8拍 电机转动一圈
//记录当前步数
if(i==7) step_count--;
if( step_count <= 0 ) step_count = 0;
}
}
/*******************************************************************
* 函 数 名 称:step_motor45_ccw
* 函 数 说 明:四相五线步进电机逆时针转动
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:T
* 备 注:逆时针,转动顺序:b- a- b+ a+
*******************************************************************/
void step_motor45_ccw( void )
{
static uint8_t i=0;
//如果开启了逆时针动作
if( motor_ccw_flag == 1 )
{
AP ( ( phaseccw[i] >> 3 ) & 0x01 );
BP ( ( phaseccw[i] >> 2 ) & 0x01 );
AM ( ( phaseccw[i] >> 1 ) & 0x01 );
BM ( ( phaseccw[i] >> 0 ) & 0x01 );
i=(i+1)%8; //8拍 电机转动一圈
//记录当前步数
if(i==7) step_count++;
if( step_count >= MOTOR_STEP_MAX ) step_count = MOTOR_STEP_MAX;
}
}
/******************************************************************
* 函 数 名 称:set_step_count
* 函 数 说 明:设置当前行进步数
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:T
* 备 注:无
******************************************************************/
void set_step_count(int num)
{
step_count = num;
}
红外模块
1.实物图
2.原理
红外通信
在光谱中波长自760nm至400um的电磁波称为红外线,它是一种不可见光。红外光是以特定的频率脉冲形式发射,接收端收到到信号后,按照约定的协议进行解码,完成数据传输。在消费类电子产品里,脉冲频率普遍采用 30KHz 到 60KHz 这个频段,NEC协议的频率就是38KHZ。
接收端的原理: 接收端的芯片对这个红外光比较敏感,可以根据有没有光输出高低电平,如果发送端的闪烁频率是有规律的,接收端收到后输出的高电平和低电平也是有规律对应的,这样发送端和接收端只要约定好,那就可以做数据传输了。
NEC协议介绍
详情请参考立创开发板手册红外接收模块
3.原理图
4.数据流
5.关键点
关键是对NEC协议的处理,立创开发板手册对此有很详细的介绍,详情请参考上面链接。
6.关键代码
/************************************************
函数名称 : EXTI5_9_IRQHandler
功 能 : 红外数据接收中断函数
参 数 : 无
返 回 值 : 无
作 者 : T
备 注 :
*************************************************/
void EXTI5_9_IRQHandler(void)
{
if(exti_interrupt_flag_get(EXTI_X) == SET) // 中断标志位为1
{
if(gpio_input_bit_get(IR_PORT,IR_PIN) == RESET) // 如果是低电平
{
//接收一次红外数据
receiving_infrared_data();
}
exti_interrupt_flag_clear(EXTI_X); // 清中断标志位
}
}
语音模块(HLK-V20)
1.实物图
2.简介
HLK-V20/HLK-V20S是海凌科电子针对大量纯离线控制场景和产品最新推出的高性能纯离线语音识别模块,广泛且快速的应用于智能家居。
3.原理图
4.数据流
MIC-语音模块-Speaker
语音命令配置平台
1、MIC数据进入语音模块;
2、语音模块根据提前配置好的命令对MIC数据进行处理;
3、根据对应数据进行对应播报;
MIC-语音模块-串口-梁山派
1、MIC数据进入语音模块;
2、语音模块根据提前配置好的命令通过串口发送对应数据到梁山派;
3、梁山派根据对应命令进行相应操作;
5.关键点
关键是语音模块和梁山派通过串口进行的数据收发,立创开发板手册对此有很详细的介绍,详情请参考上面链接。
6.关键代码
/******************************************************************
* 函 数 名 称:HLK_USART_IRQHandler
* 函 数 说 明:连接HLK的串口中断服务函数
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:T
* 备 注:无
******************************************************************/
void HLK_USART_IRQHandler(void)
{
if(usart_interrupt_flag_get(HLK_USART,USART_INT_FLAG_RBNE) != RESET) // 接收缓冲区不为空
{
//接收数据
HLK_RX_BUFF[ HLK_RX_LEN ] = usart_data_receive(HLK_USART);
#if DEBUG
//测试,查看接收到了什么数据
printf("%c\r\n", HLK_RX_BUFF[ HLK_RX_LEN ]);
#endif
//0XAA 0X01 0X55
if( HLK_RX_BUFF[HLK_RX_LEN] == 0X55 )//接收到帧尾
{
if( HLK_RX_BUFF[HLK_RX_LEN-2] == 0XAA)//接收到帧头,确定数据格式正确
{
rx_data = HLK_RX_BUFF[HLK_RX_LEN-1];//接收数据
rx_flag = 1;
//printf("%c", HLK_RX_BUFF[ HLK_RX_LEN ]);
//printf("%c", HLK_RX_BUFF[ HLK_RX_LEN-1 ]);
//printf("%c\r\n", HLK_RX_BUFF[ HLK_RX_LEN-2 ]);
}
}
//接收长度限制
HLK_RX_LEN = ( HLK_RX_LEN + 1 ) % HLK_RX_LEN_MAX;
}
if(usart_interrupt_flag_get(HLK_USART,USART_INT_FLAG_IDLE) == SET) // 检测到空闲中断
{
usart_data_receive(HLK_USART); // 必须要读,读出来的值不能要
HLK_RX_BUFF[HLK_RX_LEN] = '\0'; //字符串结尾补 '\0'
HLK_RX_FLAG = SET; // 接收完成
}
}
其它说明
1、该项目会持续完善,后续的版本更新说明会放在工程的DOC文档里;
2、遇到的问题和解决方式也会放在DOC文档里;
设计图

BOM


评论