当前位置:   article > 正文

STM32驱动ADXL345三轴传感器_adxl345b stm32模拟

adxl345b stm32模拟

简介:STM32F103C8T6驱动ADXL345三轴倾斜度传感器源码介绍。

开发平台:KEIL ARM

MCU型号:STM32F103C8T6

传感器型号:ADXL345

特别提示:驱动内可能使用了某些其他组件,比如delay等,在文末外设模板下载地址内有。

1积分源码下载地址在文末!!!

接口图:

使用举例:

  1. #include <stdio.h>
  2. #include "ADXL345.h"
  3. int main()
  4. {
  5. float angleX, angleY, angleZ;
  6. ADXL345_init(); // 初始化
  7. while(1) {
  8. delayMs(1000);
  9. get_angle(&angleX, &angleY, &angleZ); // 获取三轴偏移角度
  10. printf("angle X:%f Y:%f Z:%f\n", angleX, angleY, angleZ);
  11. }
  12. }

驱动源码:

IIC.c

  1. #include "main.h"
  2. #define IIC_SDA_PORT GPIOA
  3. #define IIC_SDA_CLK (RCC_APB2Periph_GPIOA)
  4. #define IIC_SDA_PIN GPIO_Pin_5
  5. #define IIC_SCL_PORT GPIOA
  6. #define IIC_SCL_CLK (RCC_APB2Periph_GPIOA)
  7. #define IIC_SCL_PIN GPIO_Pin_6
  8. #define IIC_SCL_OUT_1 IIC_SCL_PORT->BSRR = (uint32_t)IIC_SCL_PIN // 置1
  9. #define IIC_SCL_OUT_0 IIC_SCL_PORT->BRR = (uint32_t)IIC_SCL_PIN
  10. #define IIC_SDA_OUT_1 IIC_SDA_PORT->BSRR = (uint32_t)IIC_SDA_PIN // 置1
  11. #define IIC_SDA_OUT_0 IIC_SDA_PORT->BRR = (uint32_t)IIC_SDA_PIN
  12. #define IIC_SDA_IN() ((IIC_SDA_PORT->IDR & IIC_SDA_PIN) != 0)
  13. /**
  14. * @brief IIC延时
  15. * @param None
  16. * @retval None
  17. */
  18. static void IIC_Delay(void)
  19. {
  20. uint8_t i;
  21. /* 
  22. 下面的时间是通过逻辑分析仪测试得到的。
  23. 工作条件:CPU主频72MHz ,MDK编译环境,1级优化
  24. 循环次数为10时,SCL频率 = 205KHz
  25. 循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us
  26. 循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us
  27. */
  28. for (i = 0; i < 10; i++);
  29. }
  30. /**
  31. * @brief SDA输出方向配置
  32. * @param None
  33. * @retval None
  34. */
  35. void Set_IIC_SDA_OUT(void)
  36. {
  37. GPIO_InitTypeDef GPIO_InitStructure;
  38. RCC_APB2PeriphClockCmd(IIC_SDA_CLK, ENABLE);
  39. GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;
  40. GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  41. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;
  42. GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
  43. }
  44. /**
  45. * @brief SDA输入方向配置
  46. * @param None
  47. * @retval None
  48. */
  49. void Set_IIC_SDA_IN(void)
  50. {
  51. GPIO_InitTypeDef GPIO_InitStructure;
  52. RCC_APB2PeriphClockCmd(IIC_SDA_CLK, ENABLE);
  53. GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;
  54. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
  55. GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
  56. }
  57. /**
  58. * @brief 模拟IIC初始化
  59. * @param None
  60. * @retval None
  61. */
  62. void IIC_init()
  63. {
  64. GPIO_InitTypeDef GPIO_InitStructure;
  65. RCC_APB2PeriphClockCmd(IIC_SDA_CLK | IIC_SCL_CLK, ENABLE);
  66. GPIO_InitStructure.GPIO_Pin = IIC_SDA_PIN;
  67. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
  68. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  69. GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);
  70. GPIO_InitStructure.GPIO_Pin = IIC_SCL_PIN;
  71. GPIO_Init(IIC_SCL_PORT, &GPIO_InitStructure);
  72. IIC_stop();
  73. }
  74. /**
  75. * @brief 模拟IIC起始信号
  76. * @param None
  77. * @retval None
  78. */
  79. void IIC_start()
  80. {
  81. Set_IIC_SDA_OUT();
  82. IIC_SCL_OUT_1;
  83. IIC_SDA_OUT_1;
  84. IIC_Delay();
  85. IIC_SDA_OUT_0;
  86. IIC_Delay();
  87. IIC_SCL_OUT_0;
  88. IIC_Delay();
  89. }
  90. /**
  91. * @brief 模拟IIC停止信号
  92. * @param None
  93. * @retval None
  94. */
  95. void IIC_stop()
  96. {
  97. Set_IIC_SDA_OUT();
  98. IIC_SCL_OUT_1;
  99. IIC_SDA_OUT_0;
  100. IIC_Delay();
  101. IIC_SDA_OUT_1;
  102. }
  103. /**
  104. * @brief 模拟IIC主机应答
  105. * @param None
  106. * @retval None
  107. */
  108. void IIC_ack()
  109. {
  110. Set_IIC_SDA_OUT();
  111. IIC_SDA_OUT_0;
  112. IIC_Delay();
  113. IIC_SCL_OUT_1;
  114. IIC_Delay();
  115. IIC_SCL_OUT_0;
  116. IIC_Delay();
  117. IIC_SDA_OUT_1;
  118. }
  119. /**
  120. * @brief 模拟IIC主机不应答
  121. * @param None
  122. * @retval None
  123. */
  124. void IIC_noack()
  125. {
  126. Set_IIC_SDA_OUT();
  127. IIC_SDA_OUT_1;
  128. IIC_Delay();
  129. IIC_SCL_OUT_1;
  130. IIC_Delay();
  131. IIC_SCL_OUT_0;
  132. IIC_Delay();
  133. }
  134. /**
  135. * @brief 模拟IIC等待从机应答
  136. * @param None
  137. * @retval 1: 接收应答失败 0: 接收应答成功
  138. */
  139. uint8_t IIC_wait_ack()
  140. {
  141. uint8_t rec = 0;
  142. Set_IIC_SDA_OUT();
  143. IIC_SDA_OUT_1;
  144. IIC_Delay();
  145. Set_IIC_SDA_IN();
  146. IIC_SCL_OUT_1;
  147. IIC_Delay();
  148. rec = IIC_SDA_IN();
  149. IIC_SCL_OUT_0;
  150. IIC_Delay();
  151. return rec;
  152. }
  153. /**
  154. * @brief 模拟IIC发送一个字节
  155. * @param None
  156. * @retval None
  157. */
  158. void IIC_send_byte(uint8_t txd)
  159. {
  160. uint8_t i=0;
  161. Set_IIC_SDA_OUT();
  162. for(i=0;i<8;i++)
  163. {
  164. if(txd&0x80) IIC_SDA_OUT_1;
  165. else IIC_SDA_OUT_0;
  166. IIC_Delay();
  167. IIC_SCL_OUT_1;
  168. IIC_Delay(); // 发送数据
  169. IIC_SCL_OUT_0;
  170. if(i == 7) IIC_SDA_OUT_1; // 最后一位数据发送完要释放SDA总线
  171. txd <<= 1;
  172. IIC_Delay();
  173. }
  174. }
  175. /**
  176. * @brief 模拟IIC读取一个字节
  177. * @param ack: 0,读完不产生应答 1,读完产生应答
  178. * @retval 返回读取到的字节
  179. */
  180. uint8_t IIC_read_byte(uint8_t ack)
  181. {
  182. uint8_t i,receive=0;
  183. Set_IIC_SDA_IN();
  184. for(i=0;i<8;i++)
  185. {
  186. receive <<= 1;
  187. IIC_SCL_OUT_1;
  188. IIC_Delay();
  189. if(IIC_SDA_IN()) receive++; // 连续读取八位
  190. IIC_SCL_OUT_0;
  191. IIC_Delay();
  192. }
  193. if(!ack) IIC_noack();
  194. else IIC_ack();
  195. return receive; // 返回读取到的字节
  196. }

IIC.h 

  1. #ifndef __IIC_H
  2. #define __IIC_H
  3. #include "main.h"
  4. void Set_IIC_SDA_OUT(void);
  5. void Set_IIC_SDA_IN(void);
  6. void IIC_init(void);
  7. void IIC_start(void);
  8. void IIC_stop(void);
  9. void IIC_ack(void);
  10. void IIC_noack(void);
  11. uint8_t IIC_wait_ack(void);
  12. void IIC_send_byte(uint8_t txd);
  13. uint8_t IIC_read_byte(uint8_t ack);
  14. #endif

ADXL345.c

  1. /*
  2. ADXL345三轴倾斜度模块
  3. */
  4. #include "ADXL345.h"
  5. #include "IIC.h"
  6. /**
  7. * @brief ADXL345初始化
  8. * @param None
  9. * @retval None
  10. */
  11. uint8_t ADXL345_init(void)
  12. {
  13. IIC_init();
  14. if(ADXL345_read_reg(DEVICE_ID) == 0xE5)
  15. {
  16. ADXL345_write_reg(DATA_FORMAT,0X0B); // 低电平中断输出,13位全分辨率,输出数据右对齐,16g量程
  17. ADXL345_write_reg(BW_RATE,0x0E); // 数据输出速度为100Hz
  18. ADXL345_write_reg(POWER_CTL,0x08); // 链接使能,测量模式,省电特性
  19. ADXL345_write_reg(INT_ENABLE,0x80); // 不使用中断
  20. ADXL345_write_reg(OFSX,0x00);
  21. ADXL345_write_reg(OFSY,0x00);
  22. ADXL345_write_reg(OFSZ,0x05);
  23. return 0;
  24. }
  25. return 1;
  26. }
  27. /**
  28. * @brief ADXL345写寄存器
  29. * @param None
  30. * @retval None
  31. */
  32. uint8_t ADXL345_write_reg(u8 addr,u8 val)
  33. {
  34. IIC_start();
  35. IIC_send_byte(slaveaddress); // 发送写器件指令
  36. if(IIC_wait_ack())
  37. {
  38. return 1;
  39. }
  40. IIC_send_byte(addr); // 发送寄存器地址
  41. if(IIC_wait_ack())
  42. {
  43. return 2;
  44. }
  45. IIC_send_byte(val); // 发送值
  46. if(IIC_wait_ack())
  47. {
  48. return 3;
  49. }
  50. IIC_stop(); // 产生一个停止条件
  51. return 0;
  52. }
  53. /**
  54. * @brief ADXL345读寄存器
  55. * @param None
  56. * @retval None
  57. */
  58. u8 ADXL345_read_reg(u8 addr)
  59. {
  60. u8 temp=0;
  61. IIC_start();
  62. IIC_send_byte(slaveaddress); // 发送写器件指令
  63. if(IIC_wait_ack())
  64. {
  65. return 1;
  66. }
  67. IIC_send_byte(addr); // 发送寄存器地址
  68. if(IIC_wait_ack())
  69. {
  70. return 2;
  71. }
  72. IIC_start(); // 重新启动
  73. IIC_send_byte(regaddress); // 发送读器件指令
  74. if(IIC_wait_ack())
  75. {
  76. return 3;
  77. }
  78. temp=IIC_read_byte(0); // 读取一个字节,不继续再读,发送NAK
  79. IIC_stop(); // 产生一个停止条件
  80. return temp;
  81. }
  82. /**
  83. * @brief ADXL345读取数据
  84. * @param None
  85. * @retval None
  86. */
  87. void ADXL345_read_data(short *x,short *y,short *z)
  88. {
  89. u8 buf[6];
  90. u8 i;
  91. IIC_start();
  92. IIC_send_byte(slaveaddress); // 发送写器件指令
  93. IIC_wait_ack();
  94. IIC_send_byte(0x32); // 发送寄存器地址(数据缓存的起始地址为0X32)
  95. IIC_wait_ack();
  96. IIC_start(); // 重新启动
  97. IIC_send_byte(regaddress); // 发送读器件指令
  98. IIC_wait_ack();
  99. for(i=0;i<6;i++)
  100. {
  101. if(i==5)buf[i]=IIC_read_byte(0); // 读取一个字节,不继续再读,发送NACK
  102. else buf[i]=IIC_read_byte(1); // 读取一个字节,继续读,发送ACK
  103. }
  104. IIC_stop(); // 产生一个停止条件
  105. *x=(short)(((u16)buf[1]<<8)+buf[0]); // 合成数据
  106. *y=(short)(((u16)buf[3]<<8)+buf[2]);
  107. *z=(short)(((u16)buf[5]<<8)+buf[4]);
  108. }
  109. /**
  110. * @brief ADXL345连读读取几次取平均值
  111. * @param None
  112. * @retval None
  113. */
  114. void ADXL345_read_average(short *x,short *y,short *z,u8 times)
  115. {
  116. u8 i;
  117. short tx,ty,tz;
  118. *x=0;
  119. *y=0;
  120. *z=0;
  121. if(times)//读取次数不为0
  122. {
  123. for(i=0;i<times;i++)//连续读取times次
  124. {
  125. ADXL345_read_data(&tx,&ty,&tz);
  126. *x+=tx;
  127. *y+=ty;
  128. *z+=tz;
  129. DELAYClass.DelayMs(5);
  130. }
  131. *x/=times;
  132. *y/=times;
  133. *z/=times;
  134. }
  135. }
  136. /**
  137. * @brief ADXL345计算角度
  138. * @param None
  139. * @retval None
  140. */
  141. void get_angle(float *x_angle,float *y_angle,float *z_angle)
  142. {
  143. short ax,ay,az;
  144. ADXL345_read_average(&ax,&ay,&az,10);
  145. *x_angle=atan(ax/sqrt((az*az+ay*ay)))*180/3.14;
  146. *y_angle=atan(ay/sqrt((ax*ax+az*az)))*180/3.14;
  147. *z_angle=atan(sqrt((ax*ax+ay*ay)/az))*180/3.14;
  148. }

ADXL345.h

  1. #ifndef __ADXL345_H
  2. #define __ADXL345_H
  3. #include "main.h"
  4. #define X_AXLE 0 //x轴
  5. #define Y_AXLE 1 //y轴
  6. #define Z_AXLE 2 //z轴
  7. #define slaveaddress 0xA6 //定义器件在IIC总线中的从地址,根据ALT ADDRESS地址引脚不同修改
  8. // ALT ADDRESS引脚接地时地址为0xA6,接电源时地址为0x3A
  9. #define THRESH_TAP 0X1D //敲击中断阈值(用于正常敲击检测)
  10. // 16g模式中,62.5mg/Bit
  11. #define OFSX 0X1E //X轴偏移寄存器 15.6mg/Bit 0xff = 4g
  12. #define OFSY 0X1F //X轴偏移寄存器 15.6mg/Bit 0xff = 4g
  13. #define OFSZ 0X20 //X轴偏移寄存器 15.6mg/Bit 0xff = 4g
  14. #define DUR 0x21 //敲击阈值时间 625uS/Bit
  15. #define LATENT 0X22 //敲击事件到时间窗口的延迟时间,在此期间
  16. // 可检测第二次敲击时间 1.25mg/Bit
  17. #define WINDOW 0X23 //敲击窗口,延迟时间满后的时间量,在此期间
  18. // 能开始进行第二次有效敲击 1.25mg/Bit
  19. #define THRESH_ACT 0X24 //检测活动的阈值,活动事件的幅度与该寄存器
  20. // 的值进行比较 62.5mg/Bit
  21. #define THRESH_INACT 0X25 //检测静止的阈值,静止事件的幅度与该寄存器
  22. // 的值进行比较 62.5mg/Bit
  23. #define TIME_INACT 0X26 //加速度时间量小于该寄存器的值表示静止 1S/Bit
  24. #define ACT_INACT_CTL 0X27
  25. //Bit 7,3 ACT交流/直流[INACT交流/直流]:0选择直流耦合;1使能交流耦合 直流时将
  26. // 当前加速度值直接与THRESH_ACT和THRESH_INACT
  27. // 进行比较,确定检测到的是活动还是静止
  28. // 6,2 ACT_X使能[INACT_X使能]:设置为1,使能X轴参与检测活动或静止;活动检测时,
  29. // 所有轴为逻辑"或",有任意轴超过阈值时,活动功能触发
  30. // 禁止检测时,所有轴为逻辑"与",只有当所有轴低于阈值
  31. // 时,静止功能触发
  32. // 5,1 ACT_Y使能[INACT_Y使能]:与X轴类似
  33. // 4,0 ACT_Z使能[INACT_Z使能]:与X轴类似
  34. #define THRESH_FF 0X28 //阈值,用于自由落体检测,所有轴加速度与该寄存器值比较
  35. // ,以确定是否发生自由落体 62.5mg/Bit,建议300mg与600mg之间
  36. #define TIME_FF 0X29 //维持THRESH_FF阈值的最小时间,以生成自由落体中断 5mS/Bit
  37. #define TAP_AXES 0X2A
  38. // Bit 7:4 0
  39. // 3 抑制 两次敲击之间出现大于THRESH_TAP值得加速度,设置抑制会抑制双击检测
  40. // 2 TAP_X使能 设置为1时,使能X轴进行敲击检测,0时排除该轴的敲击检测
  41. // 1 TAP_Y使能 设置为1时,使能Y轴进行敲击检测,0时排除该轴的敲击检测
  42. // 0 TAP_Z使能 设置为1时,使能Z轴进行敲击检测,0时排除该轴的敲击检测
  43. #define ACT_TAP_STATUS 0X2B /*只读寄存器*/
  44. // Bit 7 0
  45. // 6,2 ACT_X来源,TAP_X来源:表示涉及敲击或活动事件的第一轴,设置为1时,对应事件参与
  46. // 设置为0时,对应未参与.不会自动清零,新数据覆盖,中断清零前
  47. // 应读取该寄存器
  48. // 5,1 ACT_Y来源,TAP_Y来源:与X相似
  49. // 4,0 ACT_Z来源,TAP_Z来源:与X相似
  50. // 3 休眠设置为1时,器件进入休眠状态
  51. #define BW_RATE 0X2C
  52. // Bit 7:5 0
  53. // 4 LOW_POWER 低功耗位,0选择正常模式,1进入低功耗模式
  54. // 3:0 速率位
  55. #define POWER_CTL 0X2D
  56. // Bit 7,6 0
  57. // 5 链接 设置1时,延迟活动开始,直到检测到静止.检测到活动后,禁止检测开始,活动
  58. // 检测停止,设置时动态链接活动和静止交替检测;设置0时静止与活动同时检测
  59. // 4 AUTO_SLEEP 设置1时自动休眠,检测出静止后,进行休眠模式,活动使能后被唤醒
  60. // 3 测量 0待机 1测量模式
  61. // 2 休眠 0普通 1休眠
  62. // 1,0 唤醒(休眠模式下的读取频率) "00":8HZ "01":4HZ "10":2HZ "11":1HZ
  63. #define INT_ENABLE 0X2E //中断使能配置
  64. // Bit 7 DATA_READY
  65. // 6 SINGLE_TAP
  66. // 5 DOUBLE_TAP
  67. // 4 Activity
  68. // 3 Inactivity
  69. // 2 FREE_FALL 自由落体中断
  70. // 1 Watermark
  71. // 0 Overrun
  72. #define INT_MAP 0X2F //中断映射 自读寄存器
  73. //位与INT_ENABLE对应,,设置为0,该中断映射到INT1引脚;设置为1,该中断映射到INT2引脚
  74. #define INT_SOURCE 0X30 //中断来源
  75. //位与INT_ENABLE对应,1表示该功能触发
  76. #define DATA_FORMAT 0X31
  77. // Bit 7 SELF_TEST 设置1,自测力应用至传感器,造成输出数据转换;0时禁用自测力
  78. // 6 SPI 1设置为3线SPI模式,0时设置4线SPI模式
  79. // 5 INT_INVERT 0时中断高电平有效,1时低电平有效
  80. // 4 0
  81. // 3 FULL_RES 1时设置全分辨率模式,输出以4mg/Bit增加;0时为10位模式
  82. // 2 Justify 1为左对齐模式;8为右对齐模式,并带有符号扩展
  83. // 1:0 范围位 "00"±2g "01"±4g "10"±8g "11"±16g
  84. #define DATAX0 0X32
  85. #define DATAX1 0X33 //与DATAX0组成x轴输出数据(二进制补码),DATAX1为高位,4mg/Bit
  86. #define DATAY0 0X34
  87. #define DATAY1 0X35 //与DATAY0组成Y轴输出数据(二进制补码),DATAY1为高位,4mg/Bit
  88. #define DATAZ0 0X36
  89. #define DATAZ1 0X37 //与DATAZ0组成Z轴输出数据(二进制补码),DATAZ1为高位,4mg/Bit
  90. #define FIFO_CTL 0X38
  91. // Bit 7,6 FIFO_MODE "00" 旁路模式
  92. // "01" FIFO模式 可收集最多32个值,然后停止收集数据
  93. // "10" 流模式 FIFO保存最后32个数据值,FIFO满时,新数据覆盖最早数据(先进先出)
  94. // "11" 触发器 通过触发位触发,FIFO在触发事件前保存最后的数据样本,然后
  95. // 继续收集数据直到填满;填满后,不再收集新数据
  96. // 5 触发位 0链接触发器模式下的触发事件至INT1,1链接至INT2
  97. // 4:0 样本 功能取决于FIFO模式:FIFO模式时,指定触发水印中断需要的FIFO条目数
  98. // 流模式时,指定触发水印中断需要的FIFO条目数
  99. // 触发器模式:指定触发事件之前在FIFO缓冲区要保留的FIFO样本数
  100. // 样本位设置为0时,不管哪种FIFO模式,立即在INT_SOURCE寄存器设置水印状态位
  101. #define FIFO_STATUS 0X39 /*只读寄存器*/
  102. // Bit 7 FIFO_TRIG FIFO_TRIG为1时表示有触发事件发生
  103. // 6 0
  104. // 5:0 条目位 报告FIFO存储的数据值的数量
  105. //#define slaveaddress 0XA6//write
  106. #define regaddress 0XA7//read
  107. #define DEVICE_ID 0X00
  108. uint8_t ADXL345_init(void);
  109. u8 ADXL345_read_reg(u8 addr);
  110. uint8_t ADXL345_write_reg(u8 addr,u8 val);
  111. void ADXL345_read_data(short *x,short *y,short *z);
  112. void ADXL345_read_average(short *x,short *y,short *z,u8 times);
  113. void get_angle(float *x_angle,float *y_angle,float *z_angle);
  114. #endif

驱动下载地址:

https://download.csdn.net/download/m0_50669075/87672763

STM32工程模板、外设模板、模块模板下载地址:

stm32_template: STM32F103工程模板,外设模板,模块模板。模块模板包括:DHT11温湿度传感器,OLED屏幕,DS18B20温度传感器,DS1302时钟模块,红外测温模块,RFID模块,SIM900A短信模块,OneNET入网,ADXL345三轴传感器,离线语音识别模块,语音播报模块,甲醛传感器,PM2.5模块,SG90舵机,健康检测模块,消息队列示例,链表示例,分时调度系统示例等。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/507253
推荐阅读
相关标签
  

闽ICP备14008679号