[单片机芯片] 基于CH579驱动OPT300X环境光传感器

今天从同事那里拿到一个OPT300X(实际是OPT3001)环境光传感器,想让我帮忙测测模块如何驱动,今天就跟大家分享一下这个模块如何玩吧。
 

拿到这个模块发现这个模块好小啊,从接口丝印这块可以看出采用的是I2C方式进行通讯的,还引出了INT接口,不过我这次没有使用INT中断接口。通过板上的元件丝印可以看出,VCC旁边的SOT23封装是一个PMOS3400,另一个SOT23封装的芯片是622K 5V转3.3V的LDO芯片,4.7K的电阻是I2C的上拉电阻,芯片旁边的电阻是接INT中断引脚的一个上拉电阻。其他几颗是电容,作用是滤波功能。
OPT3001的特点(来源于芯片手册):
该芯片采用精密光学滤波,可与人眼相匹配:可阻隔 99%(典型值)以上的红外线
支持自动满量程设置功能可简化软件并确保进行适当配置
• 测量范围:0.01 Lux 至83,000 Lux
• 23 位有效动态范围,支持自动设置增益范围
• 12 种二进制权满量程范围设置:范围间匹配程度< 0.2%(典型值)
• 低工作电流:1.8µA(典型值)
• 工作温度范围:-40°C 至 +85°C
• 宽电源范围:1.6V 至 3.6V
• 可耐受 5.5V 电压的 I/O
• 灵活的中断系统
• 小封装尺寸:2.0mm x 2.0mm x 0.65mm
芯片手册管脚介绍如下图所示:

分析好模块的电路之后,就可以正常编程了,本次还是采用CH579开发板进行调试,采用模拟I2C的方式进行驱动,#define OPT3001_I2C_ADDR  0x44  // 7位地址,这里需要注意。
OPT3001.c
复制

  1. #include "opt3001.h"
  2. #include "CH57x_common.h"
  3. // I2C引脚定义
  4. //static uint8_t opt3001_sda_pin = GPIO_Pin_7;  // 默认引脚
  5. //static uint8_t opt3001_scl_pin = GPIO_Pin_6;
  6. // 读取SDA引脚状态
  7. static uint8_t I2C_SDA_READ(void)
  8. {
  9.     // 读取整个端口B,然后检查SDA引脚
  10.     return (GPIOB_ReadPort() & I2C_SDA_PIN) ? 1 : 0;
  11. }
  12. // I2C初始化
  13. void I2C_Init(void)
  14. {
  15.     // 设置引脚为推挽输出,初始状态为高电平
  16.     GPIOB_ModeCfg(I2C_SDA_PIN | I2C_SCL_PIN, GPIO_ModeOut_PP_5mA);
  17.     I2C_SDA_HIGH();
  18.     I2C_SCL_HIGH();
  19. }
  20. // I2C起始信号
  21. void I2C_Start(void)
  22. {
  23.     I2C_SDA_OUT();
  24.     I2C_SDA_HIGH();
  25.     I2C_SCL_HIGH();
  26.     DelayUs(5);
  27.     I2C_SDA_LOW();
  28.     DelayUs(5);
  29.     I2C_SCL_LOW();
  30.     DelayUs(5);
  31. }
  32. // I2C停止信号
  33. void I2C_Stop(void)
  34. {
  35.     I2C_SDA_OUT();
  36.     I2C_SDA_LOW();
  37.     DelayUs(5);
  38.     I2C_SCL_HIGH();
  39.     DelayUs(5);
  40.     I2C_SDA_HIGH();
  41.     DelayUs(5);
  42. }
  43. // I2C发送一个字节
  44. uint8_t I2C_SendByte(uint8_t data)
  45. {
  46.     uint8_t i, ack;
  47.    
  48.     I2C_SDA_OUT();
  49.    
  50.     for(i = 0; i < 8; i++)
  51.     {
  52.         if(data & 0x80)
  53.             I2C_SDA_HIGH();
  54.         else
  55.             I2C_SDA_LOW();
  56.         data <<= 1;
  57.         
  58.         DelayUs(2);
  59.         I2C_SCL_HIGH();
  60.         DelayUs(5);
  61.         I2C_SCL_LOW();
  62.         DelayUs(2);
  63.     }
  64.    
  65.     // 读取ACK
  66.     I2C_SDA_HIGH();
  67.     I2C_SDA_IN();
  68.     DelayUs(2);
  69.     I2C_SCL_HIGH();
  70.     DelayUs(5);
  71.    
  72.     ack = I2C_SDA_READ();  // 返回1表示NACK,0表示ACK
  73.    
  74.     I2C_SCL_LOW();
  75.     I2C_SDA_OUT();
  76.    
  77.     return ack;  // 返回ACK状态
  78. }
  79. // I2C接收一个字节
  80. uint8_t I2C_ReceiveByte(uint8_t ack)
  81. {
  82.     uint8_t i, data = 0;
  83.    
  84.     I2C_SDA_HIGH();
  85.     I2C_SDA_IN();
  86.    
  87.     for(i = 0; i < 8; i++)
  88.     {
  89.         DelayUs(2);
  90.         I2C_SCL_HIGH();
  91.         data <<= 1;
  92.         
  93.         if(I2C_SDA_READ())
  94.             data |= 0x01;
  95.         
  96.         DelayUs(5);
  97.         I2C_SCL_LOW();
  98.     }
  99.    
  100.     // 发送ACK
  101.     I2C_SDA_OUT();
  102.     if(ack)
  103.         I2C_SDA_LOW();  // 发送ACK
  104.     else
  105.         I2C_SDA_HIGH(); // 发送NACK
  106.    
  107.     DelayUs(2);
  108.     I2C_SCL_HIGH();
  109.     DelayUs(5);
  110.     I2C_SCL_LOW();
  111.     I2C_SDA_HIGH();
  112.    
  113.     return data;
  114. }
  115. // 初始化OPT3001
  116. void OPT3001_Init(void)
  117. {
  118.     I2C_Init();
  119.     DelayMs(10);  // 等待传感器稳定
  120. }
  121. ///**
  122. // * @brief 初始化OPT3001传感器
  123. // * @param sda_pin SDA引脚
  124. // * @param scl_pin SCL引脚
  125. // */
  126. //void OPT3001_Init(uint8_t sda_pin, uint8_t scl_pin)
  127. //{
  128. //    opt3001_sda_pin = sda_pin;
  129. //    opt3001_scl_pin = scl_pin;
  130. //   
  131. //    // 初始化I2C(使用软件I2C)
  132. //    GPIOB_SetBits(opt3001_sda_pin | opt3001_scl_pin);
  133. //    GPIOB_ModeCfg(opt3001_sda_pin | opt3001_scl_pin, GPIO_ModeOut_PP_5mA);
  134. //}
  135. ///**
  136. // * @brief 读取GPIO引脚状态
  137. // * @param pin 引脚编号
  138. // * @return 引脚状态:0-低电平,1-高电平
  139. // */
  140. //static uint8_t GPIO_ReadPin(uint8_t pin)
  141. //{
  142. //    // 方法1:使用GPIOB_ReadPort()函数(无参数)
  143. //    return (GPIOB_ReadPort() & pin) ? 1 : 0;
  144. //   
  145. //    // 方法2:使用GPIO_ReadPortPin()函数(如果有的话)
  146. //    // return GPIO_ReadPortPin(GPIOB_BASE, pin);
  147. //}
  148. ///**
  149. // * @brief I2C起始信号
  150. // */
  151. //static void I2C_Start(void)
  152. //{
  153. //    GPIOB_SetBits(opt3001_sda_pin);
  154. //    GPIOB_SetBits(opt3001_scl_pin);
  155. //    DelayUs(5);
  156. //    GPIOB_ResetBits(opt3001_sda_pin);
  157. //    DelayUs(5);
  158. //    GPIOB_ResetBits(opt3001_scl_pin);
  159. //}
  160. ///**
  161. // * @brief I2C停止信号
  162. // */
  163. //static void I2C_Stop(void)
  164. //{
  165. //    GPIOB_ResetBits(opt3001_sda_pin);
  166. //    GPIOB_SetBits(opt3001_scl_pin);
  167. //    DelayUs(5);
  168. //    GPIOB_SetBits(opt3001_sda_pin);
  169. //    DelayUs(5);
  170. //}
  171. ///**
  172. // * @brief I2C发送一个字节
  173. // * @param data 要发送的数据
  174. // * @return 0-ACK, 1-NACK
  175. // */
  176. //static uint8_t I2C_SendByte(uint8_t data)
  177. //{
  178. //    uint8_t i, ack;
  179. //    uint8_t port_val;
  180. //    for(i = 0; i < 8; i++)
  181. //    {
  182. //        if(data & 0x80)
  183. //            GPIOB_SetBits(opt3001_sda_pin);
  184. //        else
  185. //            GPIOB_ResetBits(opt3001_sda_pin);
  186. //        data <<= 1;
  187. //        
  188. //        DelayUs(2);
  189. //        GPIOB_SetBits(opt3001_scl_pin);
  190. //        DelayUs(5);
  191. //        GPIOB_ResetBits(opt3001_scl_pin);
  192. //        DelayUs(2);
  193. //    }
  194. //   
  195. //    // 读取ACK - 修正:使用正确的GPIO读取方式
  196. //    GPIOB_SetBits(opt3001_sda_pin);
  197. //    GPIOB_ModeCfg(opt3001_sda_pin, GPIO_ModeIN_PU);
  198. //    DelayUs(2);
  199. //    GPIOB_SetBits(opt3001_scl_pin);
  200. //    DelayUs(5);
  201. //   
  202. //    // 使用GPIOB_ReadPort()读取整个端口,然后检查指定引脚
  203. //    port_val = GPIOB_ReadPort();  // 读取端口B的值
  204. //    ack = (port_val & opt3001_sda_pin) ? 1 : 0;
  205. //   
  206. //    GPIOB_ResetBits(opt3001_scl_pin);
  207. //    GPIOB_ModeCfg(opt3001_sda_pin, GPIO_ModeOut_PP_5mA);
  208. //   
  209. //    return ack;
  210. //}
  211. ///**
  212. // * @brief I2C接收一个字节
  213. // * @param ack 是否发送ACK
  214. // * @return 接收到的数据
  215. // */
  216. //static uint8_t I2C_ReceiveByte(uint8_t ack)
  217. //{
  218. //    uint8_t i, data = 0;
  219. //    uint8_t pin_state;
  220. //   
  221. //    GPIOB_SetBits(opt3001_sda_pin);
  222. //    GPIOB_ModeCfg(opt3001_sda_pin, GPIO_ModeIN_PU);
  223. //   
  224. //    for(i = 0; i < 8; i++)
  225. //    {
  226. //        DelayUs(2);
  227. //        GPIOB_SetBits(opt3001_scl_pin);
  228. //        data <<= 1;
  229. //        
  230. //        // 读取SDA引脚状态
  231. //        pin_state = GPIOB_ReadPort();  // 读取整个端口
  232. //        if(pin_state & opt3001_sda_pin)
  233. //            data |= 0x01;
  234. //        
  235. //        DelayUs(5);
  236. //        GPIOB_ResetBits(opt3001_scl_pin);
  237. //    }
  238. //   
  239. //    // 发送ACK
  240. //    GPIOB_ModeCfg(opt3001_sda_pin, GPIO_ModeOut_PP_5mA);
  241. //    if(ack)
  242. //        GPIOB_ResetBits(opt3001_sda_pin);
  243. //    else
  244. //        GPIOB_SetBits(opt3001_sda_pin);
  245. //   
  246. //    DelayUs(2);
  247. //    GPIOB_SetBits(opt3001_scl_pin);
  248. //    DelayUs(5);
  249. //    GPIOB_ResetBits(opt3001_scl_pin);
  250. //   
  251. //    return data;
  252. //}
  253. /**
  254. * @brief 写入OPT3001寄存器
  255. * @param reg 寄存器地址
  256. * @param data 要写入的数据
  257. * @return OPT3001_Status_t 状态
  258. */
  259. static OPT3001_Status_t OPT3001_WriteRegister(uint8_t reg, uint16_t data)
  260. {
  261.                 uint8_t i;
  262.     uint8_t buffer[3];
  263.    
  264.     buffer[0] = reg;
  265.     buffer[1] = (data >> 8) & 0xFF;  // 高位在前
  266.     buffer[2] = data & 0xFF;
  267.    
  268.     I2C_Start();
  269.    
  270.     // 发送设备地址(写)
  271.     if(I2C_SendByte(OPT3001_I2C_ADDR << 1))
  272.     {
  273.         I2C_Stop();
  274.         return OPT3001_ERROR_I2C;
  275.     }
  276.    
  277.     // 发送寄存器地址和数据
  278.     for(i = 0; i < 3; i++)
  279.     {
  280.         if(I2C_SendByte(buffer[i]))
  281.         {
  282.             I2C_Stop();
  283.             return OPT3001_ERROR_I2C;
  284.         }
  285.     }
  286.    
  287.     I2C_Stop();
  288.     return OPT3001_OK;
  289. }
  290. /**
  291. * @brief 读取OPT3001寄存器
  292. * @param reg 寄存器地址
  293. * @param data 读取的数据
  294. * @return OPT3001_Status_t 状态
  295. */
  296. static OPT3001_Status_t OPT3001_ReadRegister(uint8_t reg, uint16_t *data)
  297. {
  298.                 uint8_t msb,lsb;
  299.     I2C_Start();
  300.    
  301.     // 发送设备地址(写)
  302.     if(I2C_SendByte(OPT3001_I2C_ADDR << 1))
  303.     {
  304.         I2C_Stop();
  305.         return OPT3001_ERROR_I2C;
  306.     }
  307.    
  308.     // 发送寄存器地址
  309.     if(I2C_SendByte(reg))
  310.     {
  311.         I2C_Stop();
  312.         return OPT3001_ERROR_I2C;
  313.     }
  314.    
  315.     // 重新启动
  316.     I2C_Start();
  317.    
  318.     // 发送设备地址(读)
  319.     if(I2C_SendByte((OPT3001_I2C_ADDR << 1) | 0x01))
  320.     {
  321.         I2C_Stop();
  322.         return OPT3001_ERROR_I2C;
  323.     }
  324.    
  325.     // 读取数据(高位在前)
  326.     msb = I2C_ReceiveByte(1);  // 发送ACK
  327.     lsb = I2C_ReceiveByte(0);  // 发送NACK
  328.    
  329.     I2C_Stop();
  330.    
  331.     *data = (msb << 8) | lsb;
  332.     return OPT3001_OK;
  333. }
  334. /**
  335. * @brief 读取制造商ID
  336. * @param id 制造商ID
  337. * @return OPT3001_Status_t 状态
  338. */
  339. OPT3001_Status_t OPT3001_ReadManufacturerID(uint16_t *id)
  340. {
  341.     return OPT3001_ReadRegister(OPT3001_REG_MANUFACTURER, id);
  342. }
  343. /**
  344. * @brief 读取设备ID
  345. * @param id 设备ID
  346. * @return OPT3001_Status_t 状态
  347. */
  348. OPT3001_Status_t OPT3001_ReadDeviceID(uint16_t *id)
  349. {
  350.     return OPT3001_ReadRegister(OPT3001_REG_DEVICE_ID, id);
  351. }
  352. /**
  353. * @brief 配置OPT3001
  354. * @param config 配置值
  355. * @return OPT3001_Status_t 状态
  356. */
  357. OPT3001_Status_t OPT3001_Configure(uint16_t config)
  358. {
  359.     return OPT3001_WriteRegister(OPT3001_REG_CONFIG, config);
  360. }
  361. /**
  362. * @brief 开始单次转换
  363. * @return OPT3001_Status_t 状态
  364. */
  365. OPT3001_Status_t OPT3001_StartSingleConversion(void)
  366. {
  367.     uint16_t config;
  368.     OPT3001_Status_t status;
  369.    
  370.     // 读取当前配置
  371.     status = OPT3001_ReadRegister(OPT3001_REG_CONFIG, &config);
  372.     if(status != OPT3001_OK)
  373.         return status;
  374.    
  375.     // 设置为单次转换模式
  376.     config &= ~OPT3001_CONFIG_MODE_MASK;
  377.     config |= OPT3001_CONFIG_MODE_SINGLE;
  378.    
  379.     return OPT3001_WriteRegister(OPT3001_REG_CONFIG, config);
  380. }
  381. /**
  382. * @brief 读取光照强度(lux)
  383. * @param lux 光照强度值
  384. * @return OPT3001_Status_t 状态
  385. */
  386. OPT3001_Status_t OPT3001_ReadLux(float *lux)
  387. {
  388.     uint16_t raw_data,exponent,mantissa;
  389.     OPT3001_Status_t status;
  390.    
  391.     status = OPT3001_ReadRawData(&raw_data);
  392.     if(status != OPT3001_OK)
  393.         return status;
  394.    
  395.     // 检查溢出标志
  396.     if(raw_data & 0x8000)
  397.     {
  398.         return OPT3001_ERROR_OVERFLOW;
  399.     }
  400.    
  401.     // 提取指数和尾数
  402.     exponent = (raw_data >> 12) & 0x0F;
  403.     mantissa = raw_data & 0x0FFF;
  404.    
  405.     // 计算lux值:lux = 0.01 * 2^exponent * mantissa
  406.     *lux = 0.01 * (1 << exponent) * mantissa;
  407.    
  408.     return OPT3001_OK;
  409. }
  410. /**
  411. * @brief 读取原始数据
  412. * @param raw 原始数据
  413. * @return OPT3001_Status_t 状态
  414. */
  415. OPT3001_Status_t OPT3001_ReadRawData(uint16_t *raw)
  416. {
  417.     return OPT3001_ReadRegister(OPT3001_REG_RESULT, raw);
  418. }
  419. /**
  420. * @brief 设置高限阈值
  421. * @param lux 阈值(lux)
  422. * @return OPT3001_Status_t 状态
  423. */
  424. OPT3001_Status_t OPT3001_SetHighLimit(float lux)
  425. {
  426.                 uint16_t mantissa;
  427.                 uint8_t exponent = 0;
  428.     // 将lux转换为寄存器值
  429.     uint16_t reg_value = 0;
  430.    
  431.     if(lux > 838656) lux = 838656;  // 最大值
  432.    
  433.     // 找到合适的量程
  434.     while(lux > 4095 * 0.01 * (1 << exponent) && exponent < 11)
  435.     {
  436.         exponent++;
  437.     }
  438.    
  439.     if(exponent > 11) exponent = 11;
  440.    
  441.     // 计算尾数
  442.     mantissa = (uint16_t)(lux / (0.01 * (1 << exponent)));
  443.     if(mantissa > 4095) mantissa = 4095;
  444.    
  445.     reg_value = (exponent << 12) | mantissa;
  446.    
  447.     return OPT3001_WriteRegister(OPT3001_REG_HIGH_LIMIT, reg_value);
  448. }
  449. /**
  450. * @brief 设置低限阈值
  451. * @param lux 阈值(lux)
  452. * @return OPT3001_Status_t 状态
  453. */
  454. OPT3001_Status_t OPT3001_SetLowLimit(float lux)
  455. {
  456.                 uint16_t mantissa;
  457.                 uint8_t exponent = 0;
  458.     // 实现同SetHighLimit
  459.     uint16_t reg_value = 0;
  460.    
  461.     if(lux > 838656) lux = 838656;
  462.    
  463.     while(lux > 4095 * 0.01 * (1 << exponent) && exponent < 11)
  464.     {
  465.         exponent++;
  466.     }
  467.    
  468.     if(exponent > 11) exponent = 11;
  469.    
  470.     mantissa = (uint16_t)(lux / (0.01 * (1 << exponent)));
  471.     if(mantissa > 4095) mantissa = 4095;
  472.    
  473.     reg_value = (exponent << 12) | mantissa;
  474.    
  475.     return OPT3001_WriteRegister(OPT3001_REG_LOW_LIMIT, reg_value);
  476. }
  477. /**
  478. * @brief 等待转换完成
  479. * @return OPT3001_Status_t 状态
  480. */
  481. OPT3001_Status_t OPT3001_WaitForConversion(void)
  482. {
  483.     uint16_t config;
  484.     uint32_t timeout = 1000;  // 超时时间
  485.    
  486.     do {
  487.         DelayMs(1);
  488.         if(OPT3001_ReadRegister(OPT3001_REG_CONFIG, &config) != OPT3001_OK)
  489.             return OPT3001_ERROR_I2C;
  490.             
  491.         if(timeout-- == 0)
  492.             return OPT3001_ERROR_TIMEOUT;
  493.             
  494.     } while(!(config & OPT3001_CONFIG_CRF));  // 等待转换完成标志
  495.    
  496.     return OPT3001_OK;
  497. }

OPT3001.h
复制

  1. #ifndef __OPT3001_H__
  2. #define __OPT3001_H__
  3. #include "CH57x_common.h"
  4. // 软件I2C引脚定义
  5. #define I2C_SDA_PIN   GPIO_Pin_7
  6. #define I2C_SCL_PIN   GPIO_Pin_6
  7. // 引脚操作宏
  8. #define I2C_SDA_HIGH()    GPIOB_SetBits(I2C_SDA_PIN)
  9. #define I2C_SDA_LOW()     GPIOB_ResetBits(I2C_SDA_PIN)
  10. #define I2C_SCL_HIGH()    GPIOB_SetBits(I2C_SCL_PIN)
  11. #define I2C_SCL_LOW()     GPIOB_ResetBits(I2C_SCL_PIN)
  12. #define I2C_SDA_IN()      GPIOB_ModeCfg(I2C_SDA_PIN, GPIO_ModeIN_PU)
  13. #define I2C_SDA_OUT()     GPIOB_ModeCfg(I2C_SDA_PIN, GPIO_ModeOut_PP_5mA)
  14. // OPT3001 I2C地址
  15. #define OPT3001_I2C_ADDR         0x44  // 7位地址
  16. // 寄存器地址
  17. #define OPT3001_REG_RESULT       0x00
  18. #define OPT3001_REG_CONFIG       0x01
  19. #define OPT3001_REG_LOW_LIMIT    0x02
  20. #define OPT3001_REG_HIGH_LIMIT   0x03
  21. #define OPT3001_REG_MANUFACTURER 0x7E
  22. #define OPT3001_REG_DEVICE_ID    0x7F
  23. // 配置寄存器位定义
  24. #define OPT3001_CONFIG_RN_MASK   0xF000
  25. #define OPT3001_CONFIG_RN_AUTO   0xC000  // 自动量程
  26. #define OPT3001_CONFIG_CT        0x0800  // 转换时间:0=100ms,1=800ms
  27. #define OPT3001_CONFIG_MODE_MASK 0x0600
  28. #define OPT3001_CONFIG_MODE_SHUTDOWN 0x0000  // 关机模式
  29. #define OPT3001_CONFIG_MODE_SINGLE   0x0200  // 单次转换
  30. #define OPT3001_CONFIG_MODE_CONTINUOUS 0x0600 // 连续转换
  31. #define OPT3001_CONFIG_OVF       0x0100  // 溢出标志
  32. #define OPT3001_CONFIG_CRF       0x0080  // 转换就绪标志
  33. #define OPT3001_CONFIG_FH        0x0040  // 超出高限标志
  34. #define OPT3001_CONFIG_FL        0x0020  // 低于低限标志
  35. #define OPT3001_CONFIG_L         0x0010  // 锁存器
  36. #define OPT3001_CONFIG_POL       0x0008  // 极性
  37. #define OPT3001_CONFIG_ME        0x0004  // 屏蔽使能
  38. #define OPT3001_CONFIG_FC_MASK   0x0003  // 故障计数
  39. // 量程和分辨率
  40. typedef enum {
  41.     OPT3001_RANGE_AUTO = 0xC000,
  42.     OPT3001_RANGE_40_95 = 0x0000,
  43.     OPT3001_RANGE_0_156 = 0x1000,
  44.     OPT3001_RANGE_0_625 = 0x2000,
  45.     OPT3001_RANGE_1_25 = 0x3000,
  46.     OPT3001_RANGE_2_5 = 0x4000,
  47.     OPT3001_RANGE_5 = 0x5000,
  48.     OPT3001_RANGE_10 = 0x6000,
  49.     OPT3001_RANGE_20 = 0x7000,
  50.     OPT3001_RANGE_40 = 0x8000,
  51.     OPT3001_RANGE_80 = 0x9000
  52. } OPT3001_Range_t;
  53. // 转换模式
  54. typedef enum {
  55.     OPT3001_MODE_SHUTDOWN = 0,
  56.     OPT3001_MODE_SINGLE,
  57.     OPT3001_MODE_CONTINUOUS
  58. } OPT3001_Mode_t;
  59. // 错误代码
  60. typedef enum {
  61.     OPT3001_OK = 0,
  62.     OPT3001_ERROR_I2C,
  63.     OPT3001_ERROR_TIMEOUT,
  64.     OPT3001_ERROR_OVERFLOW,
  65.     OPT3001_ERROR_NOT_READY
  66. } OPT3001_Status_t;
  67. // 函数声明
  68. //void OPT3001_Init(uint8_t sda_pin, uint8_t scl_pin);
  69. void OPT3001_Init(void);
  70. static uint8_t GPIO_ReadPin(uint8_t pin);
  71. OPT3001_Status_t OPT3001_ReadManufacturerID(uint16_t *id);
  72. OPT3001_Status_t OPT3001_ReadDeviceID(uint16_t *id);
  73. OPT3001_Status_t OPT3001_Configure(uint16_t config);
  74. OPT3001_Status_t OPT3001_StartSingleConversion(void);
  75. OPT3001_Status_t OPT3001_ReadLux(float *lux);
  76. OPT3001_Status_t OPT3001_ReadRawData(uint16_t *raw);
  77. OPT3001_Status_t OPT3001_SetHighLimit(float lux);
  78. OPT3001_Status_t OPT3001_SetLowLimit(float lux);
  79. OPT3001_Status_t OPT3001_WaitForConversion(void);
  80. #endif /* __OPT3001_H__ */

main.c
复制

  1. /********************************** (C) COPYRIGHT *******************************
  2. * File Name          : Main.c
  3. * Author             : WCH
  4. * Version            : V1.0
  5. * Date               : 2018/12/15
  6. * Description                  : 串口1收发演示
  7. *********************************************************************************
  8. * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
  9. * Attention: This software (modified or not) and binary are used for
  10. * microcontroller manufactured by Nanjing Qinheng Microelectronics.
  11. *******************************************************************************/
  12. #include "CH57x_common.h"
  13. UINT8 TxBuff[]="This is a tx exam\r\n";
  14. UINT8 RxBuff[100];
  15. UINT8 trigB;
  16. int main()
  17. {
  18.     float lux;
  19.     uint16_t manufacturer_id, device_id;
  20.     OPT3001_Status_t status;
  21.                 uint16_t config;
  22.         
  23. /* 配置串口1:先配置IO口模式,再配置串口 */   
  24.     GPIOA_SetBits(GPIO_Pin_9);
  25.     GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);                        // RXD-配置上拉输入
  26.     GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA);                // TXD-配置推挽输出,注意先让IO口输出高电平
  27.     UART1_DefInit();
  28.     // 初始化OPT3001(使用PB6-SCL, PB7-SDA)
  29.     OPT3001_Init();   
  30.         
  31. // 读取制造商ID和设备ID
  32.     status = OPT3001_ReadManufacturerID(&manufacturer_id);
  33.     if(status == OPT3001_OK)
  34.     {
  35.         printf("Manufacturer ID: 0x%04X\r\n", manufacturer_id);
  36.     }
  37.    
  38.     status = OPT3001_ReadDeviceID(&device_id);
  39.     if(status == OPT3001_OK)
  40.     {
  41.         printf("Device ID: 0x%04X\r\n", device_id);
  42.     }
  43.    
  44.     // 配置OPT3001:自动量程,单次转换模式,转换时间800ms
  45.     config = OPT3001_CONFIG_RN_AUTO |  // 自动量程
  46.                       OPT3001_CONFIG_CT |       // 800ms转换时间
  47.                       OPT3001_CONFIG_MODE_SINGLE; // 单次转换模式
  48.    
  49.     status = OPT3001_Configure(config);
  50.     if(status != OPT3001_OK)
  51.     {
  52.         printf("Configuration failed: %d\r\n", status);
  53.     }
  54.    
  55.     // 设置阈值
  56.     OPT3001_SetHighLimit(10000.0);  // 高限1000 lux
  57.     OPT3001_SetLowLimit(1.0);     // 低限10 lux
  58.    
  59.     while(1)
  60.     {
  61.         // 开始单次转换
  62.         status = OPT3001_StartSingleConversion();
  63.         if(status != OPT3001_OK)
  64.         {
  65.             printf("Start conversion failed: %d\r\n", status);
  66.             DelayMs(1000);
  67.             continue;
  68.         }
  69.         
  70.         // 等待转换完成
  71.         status = OPT3001_WaitForConversion();
  72.         if(status != OPT3001_OK)
  73.         {
  74.             printf("Wait conversion failed: %d\r\n", status);
  75.             DelayMs(1000);
  76.             continue;
  77.         }
  78.         
  79.         // 读取光照强度
  80.         status = OPT3001_ReadLux(&lux);
  81.         if(status == OPT3001_OK)
  82.         {
  83.             printf("Light: %.2f lux\r\n", lux);
  84.         }
  85.         else if(status == OPT3001_ERROR_OVERFLOW)
  86.         {
  87.             printf("Light overflow!\r\n");
  88.         }
  89.         else
  90.         {
  91.             printf("Read error: %d\r\n", status);
  92.         }
  93.         
  94.         DelayMs(2000);  // 每2秒读取一次
  95.     }
  96. #if 0       // 测试串口发送字符串
  97.     UART1_SendString( TxBuff, sizeof(TxBuff) );
  98. #endif   
  99. #if 0       // 查询方式:接收数据后发送出去
  100.     while(1)
  101.     {
  102.         len = UART1_RecvString(RxBuff);
  103.         if( len )
  104.         {
  105.             UART1_SendString( RxBuff, len );            
  106.         }
  107.     }
  108.    
  109. #endif   
  110. #if 0      // 中断方式:接收数据后发送出去
  111.     UART1_ByteTrigCfg( UART_7BYTE_TRIG );
  112.     trigB = 7;
  113.     UART1_INTCfg( ENABLE, RB_IER_RECV_RDY|RB_IER_LINE_STAT );
  114.     NVIC_EnableIRQ( UART1_IRQn );
  115. #endif   
  116.     while(1);   
  117. }
  118. void UART1_IRQHandler(void)
  119. {
  120.     UINT8 i;
  121.    
  122.     switch( UART1_GetITFlag() )
  123.     {
  124.         case UART_II_LINE_STAT:        // 线路状态错误
  125.             UART1_GetLinSTA();
  126.             break;
  127.         
  128.         case UART_II_RECV_RDY:          // 数据达到设置触发点
  129.             for(i=0; i!=trigB; i++)
  130.             {
  131.                 RxBuff[i] = UART1_RecvByte();
  132.                 UART1_SendByte(RxBuff[i]);
  133.             }
  134.             break;
  135.         
  136.         case UART_II_RECV_TOUT:         // 接收超时,暂时一帧数据接收完成
  137.             i = UART1_RecvString(RxBuff);
  138.             UART1_SendString( RxBuff, i );
  139.             break;
  140.         
  141.         case UART_II_THR_EMPTY:         // 发送缓存区空,可继续发送
  142.             break;
  143.         
  144.         case UART_II_MODEM_CHG:         // 只支持串口0
  145.             break;
  146.         
  147.         default:
  148.             break;
  149.     }
  150. }
需要注意的是,拿到这个模块之后,由于没有关于ADDR的地址设置,因此我就拿万用表测量了芯片第二引脚,发现该引脚电压在1.5V左右,我以为是悬空就默认弱上拉,因此就没处理该引脚,发现调试的时候根本没有反应,最后把该引脚接地之后发现才可以。

最后仿真发现可以正确的读取芯片的ID了。

如果被遮挡,该值会变得很小,如果有强光,则该值会变得很大。如果想要测量的lux范围变得大一些,则可以设置阈值。   
// 设置阈值
  OPT3001_SetHighLimit(10000.0);  //高限10000 lux
  OPT3001_SetLowLimit(1.0);     // 低限1 lux
总结:
1、 买模块一定要研究原理图,同时关于I2C的话一定要注意ADDR,关于OPT3001的芯片,ADDR接地则需要地址设置成0x44,如果接VDD的话需要地址设置成0x45,一般默认接地。
2、 关于I2C的话,建议是采用硬件的I2C,不过用模拟I2C的话可以很方便的移植,就是复杂在于时序的控制,如果用逻辑分析仪则可以很容易调试。

最后,基于OPT3001的驱动就调试好啦,发现还是比较容易调试的,主要在于其I2C接口比较容易对接,同时芯片资料很多才造就了这么顺利的调试。最后祝大家调试都可以很顺利,新年快乐~


 


---------------------
作者:yangjiaxu
链接:https://bbs.21ic.com/icview-3505512-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值