本文介绍了利用ADXL345中断唤醒停止模式下的STM32F103C8T6,为进一步开发计步器做准备。
从上位机串口通讯记录了整个过程, 代码中有关OLED显示屏可以不接。
1. ADXL345寄存器, 有好多,为了观察明显,这里设置了ACTIVITY和INACTIVITY模式,都能触发INT2:(ADXL345.c)
Single_Write_ADXL345(THRESH_ACT,0x20); //检测活动的阈值为2g时产生中断,认为是开始活动了
Single_Write_ADXL345(THRESH_INACT,0x01); //0.1875g,小于它,就认为是不活动
Single_Write_ADXL345(TIME_INACT,0x02); //不活动2秒,就认为是不活动中断触发
Single_Write_ADXL345(ACT_INACT_CTL,0xEE); //使能X、Y、Z三轴的Activity和Inactivity功能
Single_Write_ADXL345(INT_MAP,0x18); //00011000, Activity和Inactivity 活动都映射到INT2 Single_Write_ADXL345(INT_ENABLE,0x18); //80 DATA_READY中断开启, 10 Activity 08 inactivity
2. 观察中断是哪个活动触发的:访问寄存器:INT_SOURCE (main.c)
printf("\r\n INT_SOURCE: 0X30= %lX After Read\r\n", Single_Read_ADXL345(0X30)); //INT_SOURCE
读两遍INT_SOURCE (0X30)可以得到
INT_SOURCE: 0X30= 93 After Read 93=10010011,从右到左第1位是OVERRUN,第2位是Watermark,第5位是ACTIVITY,第8位是DATA_READY
INT_SOURCE: 0X30= 83 After Read 83=10000011,可以看到本次中断是由ACTIVITY触发的,其它三个标志位不用管它
3. STM32 的进入停机模式:(main.c)
锂电池供电的情况下最好采用停机模式。(低功耗还有待机模式, 等于从头开机运行,而行走的步数需要在唤醒后读到, 所以不用它)。
/* 进入停止模式,设置电压调节器为低功耗模式,等待中断唤醒 */
PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI);
4. 中断处理函数:(exit.c)
EXTI0_IRQHandler可以提供给一个按键,唤醒显示步数在OLED上面,包括打开显示屏。
EXTI1_IRQHandler处理的是INT2中断,setADXL345()函数记录了标志位为1,供main.c 在主循环里面进行处理
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET)
{
printf("\r\n -----------------------EXTI0_IRQHandler----------------------- \r\n");
EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE); //清除EXTI0线路挂起位
}
}
void EXTI1_IRQHandler(void)
{
//确保是否产生了EXTI Line中断
if(EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET)
{
//由于停止唤醒后使用的是HSI时钟,与原来使用的HSE时钟时的频率不一致,会影响波特率,若此处直接printf会乱码
printf("\r\n -----------------------EXTI1_IRQHandler----------------------- \r\n");
setADXL345();
//清除中断标志位
EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);
}
}
5. 主循环里的ADXL数据读取:(main.c)
由中断设置的标志位在这里处理, ReadData_x(); 读取到temp_X,temp_Y,temp_Z, 进行步数的计算。
if(getADXL345()== 1) {
reSetADXL345(); //及时读取adxl345数据
ReadData_x(); //三轴检测函数
printf("\r\n temp_X %lf. \r\n",temp_X );
printf("\r\n temp_Y %lf. \r\n",temp_Y );
printf("\r\n temp_Z %lf. \r\n",temp_Z );
printf("\r\n INT_SOURCE: 0X30= %lX After Read\r\n", Single_Read_ADXL345(0X30)); //INT_SOURCE
printf("\r\n INT_SOURCE: 0X30= %lX After Read\r\n", Single_Read_ADXL345(0X30)); //INT_SOURCE
CheckNum++;
if((temp_Y>450)||(temp_Y<-450)) //查看正常次数
{
Normal_num++; //正常次数++
printf("\r\n Normal_num %d \r\n",Normal_num );
}
else
{
Error_num++;//倾斜次数
printf("\r\n Error_num %d \r\n",Error_num );
}
if((Error_num!=0)&&(Normal_num!=0))//检测到步数
{
BuShu++; //步数脉冲量++
printf("\r\n BuShu %d \r\n",BuShu );
Error_num=0; //清除一个周期检测
Normal_num=0;
}
}
调试结果:
[14:51:28.491]收←◆
进入停止模式,A0端口按键或A1端口ADXL345->INT2可唤醒
[14:53:38.943]收←◆\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
[14:53:39.375]收←◆
已退出停止模式
temp_X 124.800003.
temp_Y 254155.203125.
temp_Z 9297.599609.
INT_SOURCE: 0X30= 93 After Read
INT_SOURCE: 0X30= 83 After Read
Normal_num 10
[14:53:40.591]收←◆
-----------------------EXTI1_IRQHandler-----------------------
[14:53:41.577]收←◆
temp_X 156.000000.
temp_Y 254155.203125.
temp_Z 9328.799805.
INT_SOURCE: 0X30= 8A After Read
INT_SOURCE: 0X30= 83 After Read
Normal_num 11
[14:53:43.771]收←◆
temp_X 187.199997.
temp_Y 254186.406250.
temp_Z 9328.799805.
INT_SOURCE: 0X30= 83 After Read
INT_SOURCE: 0X30= 83 After Read
Normal_num 12
[14:53:52.143]收←◆
进入停止模式,A0端口按键或A1端口ADXL345->INT2可唤醒
制作出来的实物图如下:
Keil代码下载:
Keil程序.7z
(211.6 KB, 下载次数: 41)
|