pca9685.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /**
  2. * pca9685.c
  3. * PCA9685 16通道PWM驱动器完整实现
  4. */
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <unistd.h>
  9. #include <fcntl.h>
  10. #include <errno.h>
  11. #include <sys/ioctl.h>
  12. #include <linux/i2c-dev.h>
  13. #include <linux/i2c.h>
  14. #include <math.h>
  15. #include "pca9685.h"
  16. /* SMBus辅助函数 */
  17. static int i2c_smbus_write_byte_data(int fd, uint8_t reg, uint8_t value) {
  18. union i2c_smbus_data data;
  19. data.byte = value;
  20. struct i2c_smbus_ioctl_data args;
  21. args.read_write = I2C_SMBUS_WRITE;
  22. args.command = reg;
  23. args.size = I2C_SMBUS_BYTE_DATA;
  24. args.data = &data;
  25. return ioctl(fd, I2C_SMBUS, &args);
  26. }
  27. static int i2c_smbus_read_byte_data(int fd, uint8_t reg) {
  28. union i2c_smbus_data data;
  29. struct i2c_smbus_ioctl_data args;
  30. args.read_write = I2C_SMBUS_READ;
  31. args.command = reg;
  32. args.size = I2C_SMBUS_BYTE_DATA;
  33. args.data = &data;
  34. if (ioctl(fd, I2C_SMBUS, &args) < 0) return -1;
  35. return data.byte & 0xFF;
  36. }
  37. int pca9685_init(pca9685_t *dev, const char *i2c_device, uint8_t addr) {
  38. uint8_t mode1;
  39. if (dev == NULL || i2c_device == NULL) return PCA9685_ERR_PARAM;
  40. memset(dev, 0, sizeof(pca9685_t));
  41. dev->addr = addr;
  42. dev->frequency = 50.0f;
  43. dev->fd = open(i2c_device, O_RDWR);
  44. if (dev->fd < 0) {
  45. perror("Failed to open I2C device");
  46. return PCA9685_ERR_OPEN;
  47. }
  48. if (ioctl(dev->fd, I2C_SLAVE, addr) < 0) {
  49. perror("Failed to set I2C slave address");
  50. close(dev->fd);
  51. dev->fd = -1;
  52. return PCA9685_ERR_ADDR;
  53. }
  54. int ret = i2c_smbus_read_byte_data(dev->fd, PCA9685_MODE1);
  55. if (ret < 0) {
  56. fprintf(stderr, "Failed to read MODE1: %s\n", strerror(errno));
  57. close(dev->fd);
  58. dev->fd = -1;
  59. return PCA9685_ERR_INIT;
  60. }
  61. printf("PCA9685 detected at 0x%02X, MODE1=0x%02X\n", addr, ret);
  62. pca9685_reset(dev);
  63. usleep(10000);
  64. if (pca9685_write_byte(dev, PCA9685_MODE2, MODE2_OUTDRV | MODE2_OCH) < 0) {
  65. close(dev->fd);
  66. dev->fd = -1;
  67. return PCA9685_ERR_INIT;
  68. }
  69. mode1 = MODE1_RESTART | MODE1_AI | MODE1_ALLCALL;
  70. if (pca9685_write_byte(dev, PCA9685_MODE1, mode1) < 0) {
  71. close(dev->fd);
  72. dev->fd = -1;
  73. return PCA9685_ERR_INIT;
  74. }
  75. usleep(5000);
  76. pca9685_set_pwm_freq(dev, 50.0f);
  77. pca9685_all_off(dev);
  78. dev->is_open = true;
  79. printf("PCA9685 initialized\n");
  80. return PCA9685_OK;
  81. }
  82. void pca9685_close(pca9685_t *dev) {
  83. if (dev == NULL || dev->fd < 0) return;
  84. pca9685_all_off(dev);
  85. close(dev->fd);
  86. dev->fd = -1;
  87. dev->is_open = false;
  88. }
  89. int pca9685_reset(pca9685_t *dev) {
  90. if (dev == NULL || dev->fd < 0) return PCA9685_ERR_PARAM;
  91. uint8_t reset_buf[2] = {0x00, 0x06};
  92. int old_addr = dev->addr;
  93. ioctl(dev->fd, I2C_SLAVE, PCA9685_GENERAL_CALL);
  94. write(dev->fd, reset_buf, 2);
  95. ioctl(dev->fd, I2C_SLAVE, old_addr);
  96. usleep(10000);
  97. return PCA9685_OK;
  98. }
  99. int pca9685_write_byte(pca9685_t *dev, uint8_t reg, uint8_t data) {
  100. if (dev == NULL || dev->fd < 0) return PCA9685_ERR_PARAM;
  101. if (i2c_smbus_write_byte_data(dev->fd, reg, data) < 0) {
  102. fprintf(stderr, "Write failed: reg=0x%02X, %s\n", reg, strerror(errno));
  103. return PCA9685_ERR_WRITE;
  104. }
  105. return PCA9685_OK;
  106. }
  107. int pca9685_read_byte(pca9685_t *dev, uint8_t reg, uint8_t *data) {
  108. if (dev == NULL || dev->fd < 0 || data == NULL) return PCA9685_ERR_PARAM;
  109. int ret = i2c_smbus_read_byte_data(dev->fd, reg);
  110. if (ret < 0) {
  111. fprintf(stderr, "Read failed: reg=0x%02X, %s\n", reg, strerror(errno));
  112. return PCA9685_ERR_READ;
  113. }
  114. *data = (uint8_t)ret;
  115. return PCA9685_OK;
  116. }
  117. int pca9685_write_bytes(pca9685_t *dev, uint8_t reg, uint8_t *data, uint8_t len) {
  118. if (dev == NULL || data == NULL || len == 0) return PCA9685_ERR_PARAM;
  119. for (uint8_t i = 0; i < len; i++) {
  120. if (pca9685_write_byte(dev, reg + i, data[i]) < 0) return PCA9685_ERR_WRITE;
  121. }
  122. return PCA9685_OK;
  123. }
  124. int pca9685_set_pwm_freq(pca9685_t *dev, float freq) {
  125. uint8_t prescale, old_mode, new_mode;
  126. if (dev == NULL || dev->fd < 0) return PCA9685_ERR_PARAM;
  127. if (freq < PCA9685_MIN_FREQ) freq = PCA9685_MIN_FREQ;
  128. if (freq > PCA9685_MAX_FREQ) freq = PCA9685_MAX_FREQ;
  129. float prescale_val = (PCA9685_OSC_FREQ / (4096.0f * freq)) - 1.0f;
  130. prescale = (uint8_t)(prescale_val + 0.5f);
  131. if (prescale < 3) prescale = 3;
  132. if (pca9685_read_byte(dev, PCA9685_MODE1, &old_mode) < 0) return PCA9685_ERR_READ;
  133. new_mode = (old_mode & ~MODE1_RESTART) | MODE1_SLEEP;
  134. if (pca9685_write_byte(dev, PCA9685_MODE1, new_mode) < 0) return PCA9685_ERR_WRITE;
  135. if (pca9685_write_byte(dev, PCA9685_PRESCALE, prescale) < 0) return PCA9685_ERR_WRITE;
  136. if (pca9685_write_byte(dev, PCA9685_MODE1, old_mode) < 0) return PCA9685_ERR_WRITE;
  137. usleep(5000);
  138. if (pca9685_write_byte(dev, PCA9685_MODE1, old_mode | MODE1_RESTART | MODE1_AI) < 0)
  139. return PCA9685_ERR_WRITE;
  140. dev->frequency = freq;
  141. printf("PWM frequency: %.1f Hz (prescale: %d)\n", freq, prescale);
  142. return PCA9685_OK;
  143. }
  144. float pca9685_get_pwm_freq(pca9685_t *dev) {
  145. return (dev == NULL) ? 0.0f : dev->frequency;
  146. }
  147. int pca9685_set_pwm(pca9685_t *dev, uint8_t channel, uint16_t on, uint16_t off) {
  148. uint8_t reg_base, data[4];
  149. if (dev == NULL || channel > 15) return PCA9685_ERR_PARAM;
  150. if (on > 4095) on = 4095;
  151. if (off > 4095) off = 4095;
  152. reg_base = PCA9685_LED0_ON_L + (channel * 4);
  153. data[0] = on & 0xFF;
  154. data[1] = (on >> 8) & 0x0F;
  155. data[2] = off & 0xFF;
  156. data[3] = (off >> 8) & 0x0F;
  157. return pca9685_write_bytes(dev, reg_base, data, 4);
  158. }
  159. int pca9685_set_pwm_duty(pca9685_t *dev, uint8_t channel, float duty_percent) {
  160. uint16_t off_value;
  161. if (duty_percent < 0.0f) duty_percent = 0.0f;
  162. if (duty_percent > 100.0f) duty_percent = 100.0f;
  163. off_value = (uint16_t)((duty_percent * 4096.0f) / 100.0f);
  164. if (off_value > 4095) off_value = 4095;
  165. return pca9685_set_pwm(dev, channel, 0, off_value);
  166. }
  167. int pca9685_set_pwm_percent(pca9685_t *dev, uint8_t channel, uint8_t percent) {
  168. return pca9685_set_pwm_duty(dev, channel, (float)percent);
  169. }
  170. int pca9685_led_on(pca9685_t *dev, uint8_t channel) {
  171. return pca9685_set_pwm(dev, channel, 0, 4095);
  172. }
  173. int pca9685_led_off(pca9685_t *dev, uint8_t channel) {
  174. return pca9685_set_pwm(dev, channel, 0, 0);
  175. }
  176. int pca9685_led_full_on(pca9685_t *dev, uint8_t channel) {
  177. uint8_t reg = PCA9685_LED0_ON_H + (channel * 4);
  178. uint8_t val;
  179. if (pca9685_read_byte(dev, reg, &val) < 0) return PCA9685_ERR_READ;
  180. val |= 0x10;
  181. return pca9685_write_byte(dev, reg, val);
  182. }
  183. int pca9685_led_full_off(pca9685_t *dev, uint8_t channel) {
  184. uint8_t reg = PCA9685_LED0_OFF_H + (channel * 4);
  185. uint8_t val;
  186. if (pca9685_read_byte(dev, reg, &val) < 0) return PCA9685_ERR_READ;
  187. val |= 0x10;
  188. return pca9685_write_byte(dev, reg, val);
  189. }
  190. int pca9685_led_brightness(pca9685_t *dev, uint8_t channel, uint8_t brightness) {
  191. uint16_t off_value = ((uint16_t)brightness * 4095) / 255;
  192. return pca9685_set_pwm(dev, channel, 0, off_value);
  193. }
  194. int pca9685_all_off(pca9685_t *dev) {
  195. if (dev == NULL) return PCA9685_ERR_PARAM;
  196. if (pca9685_write_byte(dev, PCA9685_ALL_LED_ON_L, 0) < 0) return PCA9685_ERR_WRITE;
  197. if (pca9685_write_byte(dev, PCA9685_ALL_LED_ON_H, 0) < 0) return PCA9685_ERR_WRITE;
  198. if (pca9685_write_byte(dev, PCA9685_ALL_LED_OFF_L, 0) < 0) return PCA9685_ERR_WRITE;
  199. if (pca9685_write_byte(dev, PCA9685_ALL_LED_OFF_H, 0x10) < 0) return PCA9685_ERR_WRITE;
  200. return PCA9685_OK;
  201. }
  202. int pca9685_all_on(pca9685_t *dev) {
  203. if (dev == NULL) return PCA9685_ERR_PARAM;
  204. if (pca9685_write_byte(dev, PCA9685_ALL_LED_ON_L, 0) < 0) return PCA9685_ERR_WRITE;
  205. if (pca9685_write_byte(dev, PCA9685_ALL_LED_ON_H, 0x10) < 0) return PCA9685_ERR_WRITE;
  206. if (pca9685_write_byte(dev, PCA9685_ALL_LED_OFF_L, 0) < 0) return PCA9685_ERR_WRITE;
  207. if (pca9685_write_byte(dev, PCA9685_ALL_LED_OFF_H, 0) < 0) return PCA9685_ERR_WRITE;
  208. return PCA9685_OK;
  209. }
  210. int pca9685_all_brightness(pca9685_t *dev, uint8_t brightness) {
  211. uint16_t off_value = ((uint16_t)brightness * 4095) / 255;
  212. if (dev == NULL) return PCA9685_ERR_PARAM;
  213. if (pca9685_write_byte(dev, PCA9685_ALL_LED_ON_L, 0) < 0) return PCA9685_ERR_WRITE;
  214. if (pca9685_write_byte(dev, PCA9685_ALL_LED_ON_H, 0) < 0) return PCA9685_ERR_WRITE;
  215. if (pca9685_write_byte(dev, PCA9685_ALL_LED_OFF_L, off_value & 0xFF) < 0) return PCA9685_ERR_WRITE;
  216. if (pca9685_write_byte(dev, PCA9685_ALL_LED_OFF_H, (off_value >> 8) & 0x0F) < 0) return PCA9685_ERR_WRITE;
  217. return PCA9685_OK;
  218. }
  219. int pca9685_set_mode2(pca9685_t *dev, uint8_t mode2_val) {
  220. return pca9685_write_byte(dev, PCA9685_MODE2, mode2_val);
  221. }
  222. int pca9685_set_open_drain(pca9685_t *dev, bool enable) {
  223. uint8_t mode2;
  224. if (pca9685_read_byte(dev, PCA9685_MODE2, &mode2) < 0) return PCA9685_ERR_READ;
  225. if (enable) mode2 &= ~MODE2_OUTDRV;
  226. else mode2 |= MODE2_OUTDRV;
  227. return pca9685_write_byte(dev, PCA9685_MODE2, mode2);
  228. }
  229. int pca9685_set_output_invert(pca9685_t *dev, bool invert) {
  230. uint8_t mode2;
  231. if (pca9685_read_byte(dev, PCA9685_MODE2, &mode2) < 0) return PCA9685_ERR_READ;
  232. if (invert) mode2 |= MODE2_INVRT;
  233. else mode2 &= ~MODE2_INVRT;
  234. return pca9685_write_byte(dev, PCA9685_MODE2, mode2);
  235. }
  236. void pca9685_print_status(pca9685_t *dev) {
  237. uint8_t mode1, mode2, prescale;
  238. if (dev == NULL || dev->fd < 0) {
  239. printf("Device not initialized\n");
  240. return;
  241. }
  242. pca9685_read_byte(dev, PCA9685_MODE1, &mode1);
  243. pca9685_read_byte(dev, PCA9685_MODE2, &mode2);
  244. pca9685_read_byte(dev, PCA9685_PRESCALE, &prescale);
  245. printf("\n=== PCA9685 Status ===\n");
  246. printf("Address: 0x%02X, Freq: %.1f Hz\n", dev->addr, dev->frequency);
  247. printf("MODE1: 0x%02X, MODE2: 0x%02X, PRESCALE: %d\n", mode1, mode2, prescale);
  248. printf("=====================\n\n");
  249. }
  250. int pca9685_verify_connection(pca9685_t *dev) {
  251. uint8_t mode1;
  252. if (dev == NULL || dev->fd < 0) return PCA9685_ERR_PARAM;
  253. if (pca9685_read_byte(dev, PCA9685_MODE1, &mode1) < 0) return PCA9685_ERR_READ;
  254. printf("Connection OK, MODE1=0x%02X\n", mode1);
  255. return PCA9685_OK;
  256. }