前面我们已经完成整个自动感应调色灯的软件方案设计,现在我们根据这个软件方案来看一下具体实施。
1) 距离感应模块驱动,主要用到了超声波模块US-100,接下来看一下主要用到的函数:
//定义机构体
struct us100_data{
int enable;
int poll_time;
int cmd_gpio;
int echo_gpio;
int irq;
ktime_t last_ktime;
ktime_t now_ktime;
int distance;
struct mutex data_lock;
bool data_ready;
wait_queue_head_t data_queue;
struct work_struct y;
struct delayed_work cmd_work;
};
//计算距离为毫米
static void report_work_func(struct work_struct* work){
..........
mutex_lock(&data->data_lock);
data->distance = diff_time*170*1000/1000000000UL;
mutex_unlock(&data->data_lock);
..........
}
//周期性发射超声波
static void cmd_work_func(struct work_struct* work){
.....
gpio_set_value(data->cmd_gpio,1);
udelay(12);
gpio_set_value(data->cmd_gpio,0);
.....
}
static int us100_probe(struct platform_device *pdev){
..............
result = parse_dt(pdev,data); //解析设备树
..............
data->irq = gpio_to_irq(data->echo_gpio);
result = request_irq(data->irq,hs100_interrupt_handler,IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING,"hs100_time_count",data); //申请中断
INIT_WORK(&data->report_work,report_work_func);
INIT_DELAYED_WORK(&data->cmd_work,cmd_work_func);
.............
}
2) 调色模块软件设计,主要用到了pwm控制模块pca9685,让我们看一下主要用到的函数:
//pwm的基本逻辑控制static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns){
............
//改变周期
prescale = DIV_ROUND_CLOSEST(PCA9685_OSC_CLOCK_MHZ * period_ns,
PCA9685_COUNTER_RANGE * 1000) - 1;
if (prescale >= PCA9685_PRESCALE_MIN &&
prescale <= PCA9685_PRESCALE_MAX) {
regmap_update_bits(pca->regmap, PCA9685_MODE1,
MODE1_SLEEP, MODE1_SLEEP);
regmap_write(pca->regmap, PCA9685_PRESCALE, prescale);
regmap_update_bits(pca->regmap, PCA9685_MODE1,
MODE1_SLEEP, 0x0);
...........
pca->period_ns = period_ns;
}
............
//改变duty时间
pca->duty_ns = duty_ns;
if (duty_ns < 1) {
if (pwm->hwpwm >= PCA9685_MAXCHAN)
reg = PCA9685_ALL_LED_OFF_H;
else
reg = LED_N_OFF_H(pwm->hwpwm);
regmap_write(pca->regmap, reg, LED_FULL);
return 0;
}
............
周期与duty时间相等时
if (duty_ns == period_ns) {
if (pwm->hwpwm >= PCA9685_MAXCHAN)
reg = PCA9685_ALL_LED_OFF_L;
else
reg = LED_N_OFF_L(pwm->hwpwm);
regmap_write(pca->regmap, reg, 0x0);
if (pwm->hwpwm >= PCA9685_MAXCHAN)
reg = PCA9685_ALL_LED_OFF_H;
else
reg = LED_N_OFF_H(pwm->hwpwm);
regmap_write(pca->regmap, reg, 0x0);
if (pwm->hwpwm >= PCA9685_MAXCHAN)
reg = PCA9685_ALL_LED_ON_H;
else
reg = LED_N_ON_H(pwm->hwpwm);
regmap_write(pca->regmap, reg, LED_FULL);
return 0;
}
............
}
3) 自动感应调色模块软件设计,主要是读取超声波节点的值,通过这个值来改变pwm节点的值,从而改变灯的颜色。
static const char *path[] = {
"/sys/devices/soc.0/78ba000.i2c/i2c-6/6-0040/pwm/pwmchip1/pwm0/period",
"/sys/devices/soc.0/78ba000.i2c/i2c-6/6-0040/pwm/pwmchip1/pwm0/duty",
"/sys/devices/soc.0/78ba000.i2c/i2c-6/6-0040/pwm/pwmchip1/pwm1/period",
"/sys/devices/soc.0/78ba000.i2c/i2c-6/6-0040/pwm/pwmchip1/pwm1/duty",
"/sys/devices/soc.0/78ba000.i2c/i2c-6/6-0040/pwm/pwmchip1/pwm2/period",
"/sys/devices/soc.0/78ba000.i2c/i2c-6/6-0040/pwm/pwmchip1/pwm2/duty",
"/sys/devices/soc.0/sonar.65/value",
"/sys/devices/soc.0/sonar.65/enable",
};
static const char *pvalue[] = {"1000000", "2000000", "3000000", "10000000", "20000000", "30000000"};
static const char *dvalue[] = {"1000000", "2000000", "3000000", "10000000", "20000000", "30000000"};
void r_sonar ( int num){
int fd;
int dl = 0;
int l = 0;
static int l1 = 0;
static int n = 1;
static int i = 0;
static char buf2[8] = {'\0'};
num++;
printf("The num is --------------%d\n",num);
fd = open(path[6], O_RDONLY );
if( -1 == fd ){
printf("failed to open fd: %d\n", errno);
}
if( -1 == read( fd, buf2, SIZE ) ){
printf("failed to read fd\n");
close(fd);
}
close(fd);
l = atoi(buf2);
if(l > 2000){
l = 0;
}
printf("------l-----%d\n", l);
dl = abs(l1 - l);
l1 = l;
printf("-----dl----%d\n", dl);
if(50 < dl && dl < 300){
printf("-----n-----%d\n", n);
if(n == 1)
{
w_pwm1(pvalue[4], dvalue[3]);
w_pwm2(pvalue[4], dvalue[4]);
w_pwm3(pvalue[4], dvalue[4]);
}
if(n == 2)
{
w_pwm1(pvalue[4], dvalue[4]);
w_pwm2(pvalue[4], dvalue[3]);
w_pwm3(pvalue[4], dvalue[4]);
}
if(n == 3)
{
w_pwm1(pvalue[4], dvalue[4]);
w_pwm2(pvalue[4], dvalue[4]);
w_pwm3(pvalue[4], dvalue[3]);
}
if(n == 4)
{
w_pwm1(pvalue[5], dvalue[i]);
w_pwm2(pvalue[5], dvalue[i]);
w_pwm3(pvalue[5], dvalue[i]);
i++;
if(i == 5){
i = 0;
}
n = 0;
}
if(l > 100){
printf("---n++----l=%d\n", l);
n++;
}
}
}
static int w_pwm1 (const char *period1, const char *duty_cycle1 ){
int fd1;
int fd2;
int re;
char buf3[64] = {'\0'};
fd1 = open(path[0], O_RDWR);
if ( -1 >= fd1 ){
printf("failed to open fd1\n");
return -1;
}else{
printf("open fd1=%d\n", fd1);
}
re = write(fd1, period1, 8);
if(-1 >= re){
if(errno)
{
printf("errno = %d\n", errno);
perror("fd1 write");
printf("error: %s\n",strerror(errno));
}
close(fd1);
printf("failed to write fd1\n");
return -1;
}
fd2 = open( path[1], O_RDWR );
if ( -1 >= fd2 ){
printf("failed to open fd2\n");
return -1;
}
re = write(fd2, duty_cycle1, 8);
if(-1 >= re){
if(errno)
{
printf("errno = %d\n", errno);
perror("fd2 write");
printf("error: %s\n",strerror(errno));
}
close(fd2);
printf("failed to write fd2\n");
return -1;
}
close( fd1 );
close( fd2 );
return 0;
}
static int w_pwm2 (const char *period2, const char *duty_cycle2 ){
int fd4;
int fd5;
int re;
fd4 = open( path[2], O_RDWR );
if ( -1 >= fd4 ){
printf("failed to open fd4\n");
return -1;
}
re = write (fd4, period2, 8);
if(-1 >= re){
printf("failed to write fd4\n");
close(fd4);
return -1;
}
fd5 = open( path[3], O_RDWR );
if (-1 >= fd5){
printf("failed to open fd5\n");
return -1;
}
re = write (fd5, duty_cycle2, 8);
if(-1 >= re){
printf("failed to write fd5\n");
close(fd5);
return -1;
}
close( fd4 );
close( fd5 );
return 0;
}
static int w_pwm3 (const char *period3, const char *duty_cycle3 ){
int fd7;
int fd8;
int re;
fd7 = open( path[4], O_RDWR );
if ( -1 >= fd7 ){
printf("failed to open fd7\n");
return -1;
}
re = write (fd7, period3, 8);
if(-1 >= re){
printf("failed to write fd7\n");
close(fd7);
return -1;
}
fd8 = open( path[5], O_RDWR );
if ( -1 >= fd8 ){
printf("failed to open fd8\n");
return -1;
}
re = write (fd8, duty_cycle3, 8);
if(-1 >= re){
printf("failed to write fd8\n");
close(fd8);
return -1;
}
close( fd7 );
close( fd8 );
return 0;
}
int main(void){
int res = 0;
typedef void (*sighandler_t)(int);
if(signal(SIGALRM, r_sonar) == SIG_ERR)
{
printf("The signal is failed----------\n");
}else{
r_sonar(0);
}
struct itimerval tick;
memset(&tick, 0, sizeof(tick) );
tick.it_value.tv_sec = 1;
tick.it_value.tv_usec = 0;
tick.it_interval.tv_sec = 1;
tick.it_interval.tv_usec = 0;
res = setitimer(ITIMER_REAL, &tick, NULL);
if(res){
printf("set timer failed!!/n");
}else{
printf("The timer is running--------------\n");
}
while(1);
r_sonar(0);
return 0;
}
以上就是就是根据软件方案各个模块涉及到的核心代码,后面将会在此基础上进行改善,下篇blog中将会给出主要的调试过程、操作方法及实现效果。