Leweellll 2024-04-30 18:45 采纳率: 0%
浏览 17
已结题

linux驱动,linux应用,多线程

我采用了两个线程,主要实现两个功能,一个是根据超声波采集到的距离开关灯,另一个是根据采集到的温度使蜂鸣器响,但是有bug,只能亮灭灯,蜂鸣器不响,我初步感觉是因为不能同时read?但是每一个功能单独测试均可通过,合一块就不行了,还望解答。
代码如下

#include <stdio.h>
#include <sys/types.h>     /* See NOTES */
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <linux/fb.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <dirent.h>
#include <stdlib.h>
#include <fcntl.h>
#include <poll.h>
#include <linux/videodev2.h>
#include <sys/time.h>
#include <assert.h>
#include <sys/select.h>
#include <stdlib.h>
#include <linux/fb.h>
#include <linux/ioctl.h>
#define SR04_DEVICE "/dev/zszsr04"  /* 超声波传感器设备文件 */
#define ds18b20_DEVICE "/dev/myds18b20"  /* 温湿度传感器设备文件 */
#define  led  "/dev/myled"/*led*/
#define  buffer  "/dev/zszbuffer"
#define on 1
#define off 0
#define ring 1
#define unring 0
int sr04_fd;
int ds18b20_fd;
int led_fd;
int buffer_fd;
void* sr04_thread(void* arg) {
    led_fd = open(led, O_RDWR);
    int err1;
    if (led_fd < 0)
    {
        perror("can not open led device");
        pthread_exit(NULL);
    }
    sr04_fd = open(SR04_DEVICE, O_RDWR);
    if (sr04_fd == -1) {
        perror("Failed to open sr04 device");
        pthread_exit(NULL);
    }
    while (1) {
        int ns;
        int data;
        if (read(sr04_fd, &ns, sizeof(ns)) != sizeof(ns)) {
            perror("Failed to read sr04 data");
            continue;
        }
        printf("Distance: %d mm\n", ns * 340 / 2 / 1000000);
        data=ns * 340 / 2 / 1000000;
         if(data>100){
             err1=ioctl(led_fd,off);
             printf("%d\n",err1);
         }
         else{
            err1= ioctl(led_fd,on);
             printf("%d\n",err1);
         }
         sleep(1);
     }
}
 void* ds18b20_thread(void* arg) {
     buffer_fd = open(buffer, O_RDWR);
     int err_buffer;
     if (buffer_fd < 0)
     {
         perror("can not open buffer device");
         pthread_exit(NULL);
     }
     ds18b20_fd = open(ds18b20_DEVICE, O_RDWR);
     if (ds18b20_fd == -1) {
         perror("Failed to open ds18b20 device");
         pthread_exit(NULL);
     }
     while (1) {
         // 读取温度数据
         unsigned char data[5];
         unsigned int integer;
         unsigned char decimal;
         unsigned int tem;
         if (read(ds18b20_fd, data, 5) == 5)
         {
            integer = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);
             decimal = data[4];    
             printf("get temprature: %d.%d\n", integer, decimal);
         }else
         {
            printf("get temprature: -1\n");
             continue;
         }
        tem=integer;
         if(tem>28){
             err_buffer=ioctl(buffer_fd,ring);
             printf("%d\n",err_buffer);
          }else{
             err_buffer= ioctl(buffer_fd,unring);
             printf("%d\n",err_buffer);
           }
         sleep(1);
     }
 }
int main(int argc ,char *argv[])
{
    int error;
    int cnt=0;
    int i=0;
    int ListNum;
    fd_set readfds;
    pthread_t tid1;
    pthread_t tid2;
    if(argc!=2)
    {
        printf("./app /dev/video1\n");
        return -1;
    } 
    pthread_create(&tid1, NULL, sr04_thread, NULL);
    pthread_detach(tid1);
    pthread_create(&tid2, NULL, ds18b20_thread, NULL);
    pthread_detach(tid2);
    // 创建温度传感器线程
    return 0;
}


  • 写回答

17条回答 默认 最新

  • 专家-皆知 2024-04-30 18:45
    关注

    参考免费微信小程序:皆我百晓生 作答,经由专家-皆知整理回复,如问题解决,望采纳;如仍有疑问,请评论回复。

    从你的描述和代码来看,问题可能并不是由于不能同时read导致的,因为Linux系统本身支持多线程并发读写不同的设备文件。不过,确实存在一些潜在的问题和改进空间,我将逐一分析并提出建议。

    1. 错误处理和资源释放

    首先,确保在每个线程的执行过程中正确处理错误,并且在退出线程前关闭打开的文件描述符。这有助于避免资源泄露。

    2. IOCTL命令的正确性

    你的代码中使用了ioctl函数来控制LED和蜂鸣器,但没有展示这两个设备的驱动程序部分,也没有具体定义onoffringunring对应的宏实际是如何映射到特定操作的。确保这些操作在驱动层已经被正确实现并且与你的ioctl命令相匹配。

    3. 确认设备操作逻辑

    • 对于LED控制部分,逻辑看起来是合理的:如果距离大于100mm则关闭LED,否则打开。
    • 对于蜂鸣器控制部分,也是基于温度高于28度时响铃,否则静音。理论上这个逻辑也是正确的,除非驱动层面没有正确处理这些ioctl请求。

    4. 代码修改建议

    a. 增加错误处理和资源释放

    修改线程函数,在线程结束时关闭文件描述符。

    void* sr04_thread(void* arg) {
        ...
        while (1) {
            ...
        }
        close(led_fd);
        close(sr04_fd);
        pthread_exit(NULL);
    }
    
    void* ds18b20_thread(void* arg) {
        ...
        while (1) {
            ...
        }
        close(buffer_fd);
        close(ds18b20_fd);
        pthread_exit(NULL);
    }
    

    b. 检查ioctl命令定义和驱动实现

    确保在驱动代码中,对于onoffringunring的定义与应用层调用一致,并且驱动的ioctl处理函数逻辑正确无误。

    5. 其他可能的问题

    • 竞态条件:虽然看起来不太像由竞态条件引起,但确保你的驱动程序在处理并发读写时是线程安全的,特别是在更新共享状态(如GPIO状态)时。
    • 资源冲突:检查是否有其他进程或硬件问题导致的资源冲突,比如I2C总线上的冲突,尽管这通常会伴随错误信息。

    结论

    鉴于你的描述和代码逻辑,问题很可能不在多线程并发读取上,而是与具体的设备驱动实现或ioctl命令的正确性有关。建议仔细检查驱动程序逻辑,确认ioctl命令的正确映射,以及增加更详细的错误日志输出来辅助诊断。如果以上步骤都确认无误,考虑是否存在硬件连接或配置上的问题。

    评论 编辑记录

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 5月3日
  • 创建了问题 4月30日

悬赏问题

  • ¥15 前端echarts坐标轴问题
  • ¥15 CMFCPropertyPage
  • ¥15 ad5933的I2C
  • ¥15 请问RTX4060的笔记本电脑可以训练yolov5模型吗?
  • ¥15 数学建模求思路及代码
  • ¥50 silvaco GaN HEMT有栅极场板的击穿电压仿真问题
  • ¥15 谁会P4语言啊,我想请教一下
  • ¥15 这个怎么改成直流激励源给加热电阻提供5a电流呀
  • ¥50 求解vmware的网络模式问题 别拿AI回答
  • ¥24 EFS加密后,在同一台电脑解密出错,证书界面找不到对应指纹的证书,未备份证书,求在原电脑解密的方法,可行即采纳