通過USB攝像頭拍攝JPG照片


一、前言

  本文中的程序適用於Ubuntu或者ARM linux平台上外接USB攝像頭,將攝像頭插入USB口后在/dev目錄下會出現名為video*的設備。需要注意的是,電腦自帶的USB設備也可以接入Ubuntu系統中,並且在/dev目錄下也會出現名為video*的設備,但是本文的例程不適用於電腦自帶的攝像頭。

二、代碼

  1 /**
  2  * filename: camera.c
  3  * author: Suzkfly
  4  * date: 2021-08-15
  5  * platform: S3C2416或Ubuntu
  6  * 程序運行成功后會在當前目錄下生成pic.jpg文件,如果在Ubuntu上運行,需要超級用權限。
  7  */
  8 #include <stdio.h>
  9 #include <stdlib.h>
 10 #include <string.h>
 11 #include <getopt.h>           
 12 #include <fcntl.h>             
 13 #include <unistd.h>
 14 #include <errno.h>
 15 #include <malloc.h>
 16 #include <sys/stat.h>
 17 #include <sys/types.h>
 18 #include <sys/time.h>
 19 #include <sys/mman.h>
 20 #include <sys/ioctl.h>
 21 #include <asm/types.h>         
 22 #include <linux/videodev2.h>
 23 #include <time.h>
 24 
 25 /** <\brief 定義攝像頭設備路徑 */
 26 #define CAMERA_DEV  "/dev/video0"
 27 
 28 /** <\brief 定義清零數據的宏 */
 29 #define CLEAR(x) memset (&(x), 0, sizeof (x))
 30 
 31 /** <\brief 定義保存攝像頭數據的結構體 */
 32 struct buffer {
 33     void * start;   /* 起始地址 */
 34     size_t length;  /* 數據長度 */
 35 };
 36 
 37 #define BUFFER_CNT 4    /* 緩沖幀的個數 */
 38 
 39 /**
 40  * \brief 初始化v4l2
 41  *
 42  * \param[in] p_dev_name:攝像頭所處路徑
 43  * \param[out] p_fd:得到的攝像頭設備文件描述符
 44  * \param[out] pp_buffers:得到的緩沖幀的地址,注意這是一個二級指針,該變量保存的數據是一個地址
 45  *
 46  * \retval 成功返回0,失敗返回-1
 47  */
 48 int v4l2_init(const char *p_dev_name, int *p_fd, struct buffer **pp_buffers)
 49 {
 50     int fd = -1;
 51     struct v4l2_capability cap;
 52     struct v4l2_format fmt;
 53     enum v4l2_buf_type type;
 54     struct v4l2_requestbuffers req;
 55     time_t t;
 56     struct tm *ptm;
 57     unsigned int i;
 58        struct v4l2_buffer buf;   //驅動中的一幀
 59     
 60     /* 打開攝像頭設備 */
 61     if ((fd = open (p_dev_name, O_RDWR | O_NONBLOCK, 0)) < 0) {
 62         perror("fail to open\n");
 63         return -1;
 64     }
 65 
 66     /* ioctl是一個強大的函數,它的功能取決於傳入的第2個參數,這里第2個參數傳入
 67        VIDIOC_QUERYCAP表示獲取設備屬性,獲取到的屬性會保存在第3個參數中,第3個
 68        參數是一個struct v4l2_capability類型的結構體指針,struct v4l2_capability
 69        結構定義如下:
 70        struct v4l2_capability
 71        {
 72            u8 driver[16];         // 驅動名字
 73            u8 card[32];         // 設備名字
 74            u8 bus_info[32];     // 設備在系統中的位置
 75            u32 version;         // 驅動版本號
 76            u32 capabilities;     // 設備支持的操作
 77            u32 reserved[4];     // 保留字段
 78        };
 79        
 80        capabilities是能力的意思,其中支持的能力如下所示:
 81        #V4L2_CAP_VIDEO_CAPTURE            0x00000001  //是視頻采集設備
 82        #V4L2_CAP_VIDEO_OUTPUT            0x00000002  //是視頻輸出設備
 83        #V4L2_CAP_VIDEO_OVERLAY            0x00000004  //可以做視頻疊加
 84        #V4L2_CAP_VBI_CAPTURE            0x00000010  //是一個原始的 VBI 捕獲設備
 85        #V4L2_CAP_VBI_OUTPUT                0x00000020  //是一個原始的 VBI 輸出設備
 86        #V4L2_CAP_SLICED_VBI_CAPTURE        0x00000040  //是一個切片(sliced)的 VBI 捕獲設備
 87        #V4L2_CAP_SLICED_VBI_OUTPUT        0x00000080  //是一個切片(sliced)的 VBI 輸出設備
 88        #V4L2_CAP_RDS_CAPTURE            0x00000100  //RDS數據采集
 89        #V4L2_CAP_VIDEO_OUTPUT_OVERLAY    0x00000200  //可以做視頻輸出疊加
 90        #V4L2_CAP_HW_FREQ_SEEK            0x00000400  //可以做硬件尋頻
 91        
 92        #V4L2_CAP_TUNER                    0x00010000  //有一個協調器
 93        #V4L2_CAP_AUDIO                    0x00020000  //支持音頻
 94        #V4L2_CAP_RADIO                    0x00040000  //是無線電設備
 95        
 96        #V4L2_CAP_READWRITE              0x01000000  //讀/寫系統調用
 97        #V4L2_CAP_ASYNCIO                0x02000000  // 異步 I/O
 98        #V4L2_CAP_STREAMING              0x04000000  // streaming I/O ioctls
 99     */
100     
101     /* 獲取設備參數 */
102     if (0 != ioctl(fd, VIDIOC_QUERYCAP, &cap)) {
103         perror("fail to ioctl\n");
104         return -1;
105     }
106 #if 0
107     printf("cap.driver = %s\n", cap.driver);
108     printf("cap.card = %s\n", cap.card);
109     printf("cap.bus_info = %s\n", cap.bus_info);
110     printf("cap.version = %u\n", cap.version);
111     printf("cap.capabilities = %#08x\n", cap.capabilities);
112 #endif
113     /* struct v4l2_format結構定義如下:
114     struct v4l2_format {
115         enum v4l2_buf_type type;
116         union {
117             struct v4l2_pix_format            pix;     // V4L2_BUF_TYPE_VIDEO_CAPTURE 
118             struct v4l2_window                win;     // V4L2_BUF_TYPE_VIDEO_OVERLAY
119             struct v4l2_vbi_format            vbi;     // V4L2_BUF_TYPE_VBI_CAPTURE
120             struct v4l2_sliced_vbi_format    sliced;  // V4L2_BUF_TYPE_SLICED_VBI_CAPTURE
121             __u8    raw_data[200];                   // user-defined
122         } fmt;
123     };
124     可以看出struct v4l2_format結構中有1個枚舉類型的type和一個共用體fmt,數據保存
125     在fmt中,fmt共用體中具體使用哪個結構由type的值決定,本程序中需要設置圖像格式,
126     因此type的值設為V4L2_BUF_TYPE_VIDEO_CAPTURE,使用fmt中的pix成員。
127     struct v4l2_pix_format結構定義如下:
128     struct v4l2_pix_format {
129         __u32                     width;          //圖像寬度
130         __u32                    height;         //圖像高度
131         __u32                    pixelformat;    //像素格式
132         enum v4l2_field          field;          //場格式,見下文
133         __u32                    bytesperline;    //表明緩沖區中有多少字節用於表示圖像中一行像素的所有像素值。
134         //由於一個像素可能有多個字節表示,所以 bytesperline 可能是字段 width 值的若干倍
135         __u32                      sizeimage;      //圖像大小
136         enum v4l2_colorspace    colorspace;     //色彩空間,其中V4L2_COLORSPACE_JPEG = 7
137         __u32            priv;                    //私有數據,取決於像素格式
138     };
139     pixelformat表示像素格式,可以設置的格式有很多,比如
140     #V4L2_PIX_FMT_RGB565
141     #V4L2_PIX_FMT_RGB24
142     #V4L2_PIX_FMT_YUV565
143     #V4L2_PIX_FMT_JPEG
144     #V4L2_PIX_FMT_MPEG
145     等。
146     
147     enum v4l2_field {
148         V4L2_FIELD_ANY           = 0, //驅動程序可以選擇無、頂部、底部、隔行掃描...
149         V4L2_FIELD_NONE          = 1, //此設備沒有場
150         V4L2_FIELD_TOP           = 2, //只有頂場
151         V4L2_FIELD_BOTTOM        = 3, //只有底場
152         V4L2_FIELD_INTERLACED    = 4, //兩個場交錯
153         V4L2_FIELD_SEQ_TB        = 5, //兩個場順序合並到一個緩沖區中,從上到下順序
154         V4L2_FIELD_SEQ_BT        = 6, //同上,加自上而下的順序
155         V4L2_FIELD_ALTERNATE     = 7, //兩個場交替進入單獨的緩沖區
156         V4L2_FIELD_INTERLACED_TB = 8, //兩個場交錯,頂場在前,頂場先傳輸
157         V4L2_FIELD_INTERLACED_BT = 9, //兩個場交錯,前場先傳輸,后場先傳輸
158     };  */
159     
160     /* 設置圖像格式 */
161     CLEAR(fmt);
162     fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
163     fmt.fmt.pix.width       = 800;
164     fmt.fmt.pix.height      = 600;
165     fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
166     fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
167     if (0 != ioctl(fd, VIDIOC_S_FMT, &fmt)) {
168         perror("fail to ioctl\n");
169         return -1;
170     }
171     
172     /* 設置結果可能與寫入的數值不一樣,可以打印出來看一下 */
173 #if 0
174     printf("fmt.type = %d\n", fmt.type);
175     printf("fmt.fmt.pix.width = %d\n", fmt.fmt.pix.width);
176     printf("fmt.fmt.pix.height = %d\n", fmt.fmt.pix.height);
177     printf("fmt.fmt.pix.pixelformat = %c%c%c%c\n", 
178             (fmt.fmt.pix.pixelformat >> 0) & 0xFF, 
179             (fmt.fmt.pix.pixelformat >> 8) & 0xFF,
180             (fmt.fmt.pix.pixelformat >> 16) & 0xFF,
181             (fmt.fmt.pix.pixelformat >> 24) & 0xFF
182             );
183     printf("fmt.fmt.pix.field = %d\n", fmt.fmt.pix.field);            
184     printf("fmt.fmt.pix.bytesperline = %d\n", fmt.fmt.pix.bytesperline);
185     printf("fmt.fmt.pix.sizeimage = %d\n", fmt.fmt.pix.sizeimage);
186     printf("fmt.fmt.pix.colorspace = %d\n", fmt.fmt.pix.colorspace);
187     printf("fmt.fmt.pix.priv = %d\n", fmt.fmt.pix.priv);
188     printf("V4L2_BUF_TYPE_VIDEO_CAPTURE = %d\n", V4L2_BUF_TYPE_VIDEO_CAPTURE);
189 #endif
190 
191     //file_length = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; //計算圖片大小
192 
193     /* struct v4l2_requestbuffers結構定義如下:
194     struct v4l2_requestbuffers {
195         __u32                count;      // 緩沖區內緩沖幀的數目
196         enum v4l2_buf_type  type;       // 緩沖幀數據格式
197         enum v4l2_memory    memory;     // 區別是內存映射還是用戶指針方式,
198             V4L2_MEMORY_MMAP 為內存映射, V4L2_MEMORY_USERPTR 為用戶指針
199         __u32                reserved[2];
200     }; */
201     
202     /* 向設備申請緩沖區 */
203     CLEAR (req);
204     req.count  = BUFFER_CNT;     /* \todo 為什么要申請4個緩沖幀 */
205     req.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
206     req.memory = V4L2_MEMORY_MMAP;
207     ioctl(fd, VIDIOC_REQBUFS, &req);
208 
209     if (req.count < 2) {
210            printf("Insufficient buffer memory\n"); /* 緩沖幀數量不夠 */
211     }
212     
213     /* 內存中建立對應空間 */
214     *pp_buffers = (struct buffer *)calloc(req.count, sizeof(struct buffer));
215     if (*pp_buffers == NULL) {
216         perror("calloc failed\n");
217         return -1;
218     }
219 
220     /* 得到緩沖幀的起始地址和長度 */
221     for (i = 0; i < req.count; i++) {
222         /* struct v4l2_buffer {
223                 __u32                    index;          //緩存編號
224                 enum v4l2_buf_type      type;           //視頻捕獲模式
225                 __u32                    bytesused;      //緩存已使用空間大小
226                 __u32                    flags;          //緩存當前狀態,可取下列值
227                     #V4L2_BUF_FLAG_MAPPED    0x0001  //當前緩存已經映射
228                     #V4L2_BUF_FLAG_QUEUED    0x0002    //緩存可以采集數據
229                     #V4L2_BUF_FLAG_DONE        0x0004    //緩存可以提取數據
230                     #V4L2_BUF_FLAG_KEYFRAME    0x0008    //Image is a keyframe (I-frame) 
231                     #V4L2_BUF_FLAG_PFRAME    0x0010    //Image is a P-frame 
232                     #V4L2_BUF_FLAG_BFRAME    0x0020    //Image is a B-frame 
233                     #V4L2_BUF_FLAG_TIMECODE    0x0100    //timecode field is valid 
234                     #V4L2_BUF_FLAG_INPUT    0x0200  //input field is valid 
235                 enum v4l2_field            field;
236                 struct timeval            timestamp;  //獲取第一個字節時的系統時間
237                 struct v4l2_timecode    timecode;
238                 __u32                    sequence;   //隊列中的序號
239 
240                 // memory location 
241                 enum v4l2_memory        memory;     //IO 方式,被應用程序設置
242                 union {
243                     __u32           offset;         //緩沖幀地址偏移量,只對MMAP 有效
244                     unsigned long   userptr;
245                 } m;
246                 __u32            length;             //緩沖幀長度
247                 __u32            input;
248                 __u32            reserved;
249             };
250         */
251         
252         /* 獲取緩沖幀的地址,長度 */
253            CLEAR (buf);
254            buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
255            buf.memory      = V4L2_MEMORY_MMAP;
256            buf.index       = i;
257            if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buf)) { 
258             printf ("VIDIOC_QUERYBUF error\n");
259         }
260 
261            (*pp_buffers)[i].length = buf.length;
262         /* 通過mmap建立映射關系 */
263            (*pp_buffers)[i].start  = mmap (NULL,
264                                     buf.length,
265                                     PROT_READ | PROT_WRITE,
266                                     MAP_SHARED,
267                                     fd, 
268                                     buf.m.offset);    /* 被映射內容的偏移量 */
269            if (MAP_FAILED == (*pp_buffers)[i].start) {   /* MAP_FAILED其實是((void *) -1),mmap失敗時返回 */
270                 printf ("mmap failed\n");
271         }
272     }
273 
274     for (i = 0; i < req.count; i++) {
275             CLEAR (buf);
276 
277             buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
278          buf.memory      = V4L2_MEMORY_MMAP;
279          buf.index       = i;
280 
281          /* 把幀放入隊列 */
282          if (0 != ioctl (fd, VIDIOC_QBUF, &buf)) {
283            printf ("VIDIOC_QBUF failed\n");
284          }
285     }
286 
287     /* 開始捕捉圖像數據 */
288     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
289     if (-1 == ioctl (fd, VIDIOC_STREAMON, &type)) {
290        printf ("VIDIOC_STREAMON failed\n");
291     }
292     
293     *p_fd = fd;
294     
295     return 0;
296 }
297 
298 /**
299  * \brief v4l2去除初始化
300  *
301  * \param[in] camera_fd:打開的攝像頭設備文件描述符
302  * \param[in] p_buffers:緩沖幀地址
303  *
304  * \retval 成功返回0,失敗返回-1
305  */
306 void v4l2_deinit(int camera_fd, struct buffer *p_buffers)
307 {
308     int i;
309 
310     /* 解除映射關系 */
311     for (i = 0; i < BUFFER_CNT; i++) {
312        if (-1 == munmap (p_buffers[i].start, p_buffers[i].length)) {
313             printf ("munmap error\n");
314        }
315     }
316     
317     /* 釋放申請的內存 */
318     free(p_buffers);
319     
320     /* 關閉文件 */
321     close(camera_fd);
322 }
323 
324 /**
325  * \brief 讀取一幀數據
326  *
327  * \param[in] camera_fd:打開攝像頭設備得到的文件描述符
328  * \param[in] p_buffers:緩沖幀地址
329  * \param[in] filename:保存的jpg圖片的路徑
330  *
331  * \retval 成功返回0,失敗返回-1
332  */
333 static int __read_frame (int camera_fd, struct buffer *p_buffers, char *filename)
334 {
335     FILE *file_fd = NULL;
336     struct v4l2_buffer buf;
337     unsigned int i;
338 
339     /* 以"w+"方式打開文件,如果文件不存在則會創建文件,但前提是文件所在目錄對於
340        其他用戶有寫權限,可以用umask命令查看和修改掩碼 */
341     if((file_fd = fopen(filename, "w+")) == NULL) {
342         perror("fail to fopen\n");
343         return -1;
344     }
345 
346     /* 從隊列中取出幀 */
347     CLEAR(buf);
348     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
349     buf.memory = V4L2_MEMORY_MMAP;
350     ioctl(camera_fd, VIDIOC_DQBUF, &buf);
351     
352     fwrite(p_buffers[buf.index].start, p_buffers[buf.index].length, 1, file_fd); //將其寫入文件中
353     
354     ioctl(camera_fd, VIDIOC_QBUF, &buf); /* 把幀放入隊列 */
355 
356     fclose(file_fd);
357     
358     return 0;
359 }
360 
361 /**
362  * \brief 得到一張jpg圖片 
363  *
364  * \param[in] camera_fd:打開攝像頭設備得到的文件描述符
365  * \param[in] p_buffers:緩沖幀地址
366  * \param[in] filename:保存的jpg圖片的路徑
367  *
368  * \retval 成功返回0,失敗返回-1
369  */
370 int camera_jpg (int camera_fd, struct buffer *p_buffers, char *filename)
371 {
372     unsigned int i;
373     fd_set fds;
374     struct timeval tv;
375     int r;
376     
377     /* 設定超時時間 */
378     tv.tv_sec = 2;
379     tv.tv_usec = 0;
380 
381     while (1) { //這一段涉及到異步IO
382         FD_ZERO (&fds);     //將指定的文件描述符集清空
383         FD_SET (camera_fd, &fds);  //在文件描述符集合中增加一個新的文件描述符
384         
385         /* select函數執行成功返回集合內包含的文件描述符數量,失敗返回-1,超時返回0 */
386         r = select (camera_fd + 1, &fds, NULL, NULL, &tv);//判斷是否可讀(即攝像頭是否准備好),tv是定時
387 
388         if (-1 == r) {
389             if (EINTR == errno) {   /* 系統調用被中斷 */
390                 continue;
391             }
392             printf ("select err\n");
393             return -1;
394         } else if (0 == r) {        /* 超時 */
395             fprintf (stderr, "select timeout\n");
396             return -1;
397         }
398         
399         /* 如果可讀,__read_frame()函數,並跳出循環 */
400         return __read_frame(camera_fd, p_buffers, filename);
401     }
402     
403     return 0;
404 }
405 
406 #if 1
407 /* 將攝像頭拍到的照片保存成pic.jpg文件 */
408 int main(int argc, const char *argv[])
409 {
410     int camera_fd = 0;                  /* 攝像頭設備的文件描述符 */
411     struct buffer *  p_buffers = NULL;    /* 用於保存緩沖幀地址和長度 */
412     
413     if (0 != v4l2_init(CAMERA_DEV, &camera_fd, &p_buffers)) {
414         perror("v4l2_init failed\n");
415         return 0;
416     }
417     camera_jpg(camera_fd, p_buffers, "pic.jpg");
418 
419     v4l2_deinit(camera_fd, p_buffers);
420     
421     return 0;
422 }
423 
424 #else
425 /* 將攝像頭拍攝的照片實時顯示出來,需要將jpg.c一同編譯,要加-ljpeg選項 */
426 extern int framebuffer_init (void);
427 extern int show_jpg(unsigned int x, unsigned int y, const char *name);
428 
429 int main(int argc, const char *argv[])
430 {
431     int camera_fd = 0;                  /* 攝像頭設備的文件描述符 */
432     struct buffer *  p_buffers = NULL;    /* 用於保存緩沖幀地址和長度 */
433     
434     framebuffer_init();
435     if (0 != v4l2_init(CAMERA_DEV, &camera_fd, &p_buffers)) {
436         perror("v4l2_init failed\n");
437         return 0;
438     }
439     
440     while (1) {
441         camera_jpg(camera_fd, p_buffers, "pic.jpg");
442         show_jpg(0, 0, "pic.jpg");
443     }
444     
445     v4l2_deinit(camera_fd, p_buffers);
446     
447     return 0;
448 }
449 #endif

  程序運行后,在當前路徑下會出現名為pic.jpg的文件,這就是用攝像頭拍攝到的照片。如果使用代碼最后面的main函數,可以將拍攝到的照片直接在屏幕上顯示出來,但是要支持jpg圖片的顯示。通過framebuffer顯示jpg圖片可以參考我這篇博客:framebuffer顯示jpg圖片。但是用這種方式顯示出來的圖片是一卡一卡的,應該是處理器性能不夠強大,再者,攝像頭本來就支持視頻顯示的,本文中的例程是取出攝像頭拍攝到的畫面,保存成jpg文件,再將圖片顯示出來,這個過程做了很多多余的事情,因此顯示出來是一卡一卡的。

三、問題解答

  如果使用nfs掛載運行該程序,那么很容易出現下面兩個問題。

  1. 運行程序時,如果pic.jpg不存在,那么在調用fopen打開pic.jpg時會打開失敗,並且報錯“Permission denied”。

  既然報“Permission denied”,那顯然就是權限問題。(有些人可能會覺得是文件不存在導致的,但是本程序使用fopen打開文件,傳入的標志是“w+”,這個標志在文件不存在時會自己創建文件,而且如果是文件不存在,那么會直接報“No such file or directory”,而不是“Permission denied”。)

   要解決這個問題,有2種方法

  1)在Ubuntu上用touch命令手動創建pic.jpg文件。

  (因為nfs目錄下的文件是Ubuntu的,因此只能在Ubutnu上創建,在開發板終端沒有權限創建文件)。創建完成之后可以用ls -l命令查看文件權限,此時pic.jpg的權限為“rw-rw-r--”,為什么是這個權限呢,首先,文件權限和umask有關,可以在終端上直接輸入umask命令,可以看到終端打印出來“0002”,這表示其他用戶是沒有寫權限的。另外使用touch命令創建的文件都是沒有執行權限的,因此創建出來的文件權限為“rw-rw-r--”。所以創建出來的文件還需要使用chmod 0666 pic.jpg命令,讓其他用戶有寫權限。這樣再在開發板端運行程序就沒問題了。但是這種方法缺點很明顯,就是如果改變了文件名,那么又要進行一遍這樣的操作,或者如果需要一次性拍很多張照片,這種方法就不適用了。

  2)通過程序自動創建文件。

  前面已經說了,如果pic.jpg文件是不存在的,那么程序運行時報沒有權限的錯誤,既然是創建文件時需要權限,就應該看看希望被創建的文件所處的文件夾有沒有寫權限,如果沒有的話,使用chmod加入寫權限。之后運行程序,發現文件可以自動創建。

  但是這又帶來一個新的問題,就是文件的所有者變成了nobody,組變成了nogroup,如下圖。

  

   暫時不知道這種情況會帶來什么后果,但是這個是可以解決的,解決辦法如下:

  在Ubuntu終端中,輸入sudu vi /etc/exports

  文件的最后一行寫的是nfs共享目錄的路徑也權限等信息,在其中加入一項:no_root_squash,修改過后如下圖:

  

   注意各項中間用逗號分隔,且沒有空格。保存文件,使用命令:sudo /etc/init.d/nfs-kernel-server restart重啟nfs服務。

  之后再在開發板上運行程序,這時創建出來的文件的用戶和組都變成了root。

 

  2. 程序運行一段時間就死了,經過統計,問題會有下面幾種:

  1)程序運行時報錯:

  

   然后程序自動退出,但系統沒有死掉,並且可以再次用a.out運行程序,但程序運行一段時間后還是會死掉。

  2)程序運行時報錯,如下圖:

  

  並且系統死掉,需要重啟,但問題又來了,重啟也不一定成功,可能需要多次斷電上電才能成功重啟。

  最氣的是,重燒系統之后這個問題就沒再出現了。

  雖然問題沒再出現了,但是沒有找到出現問題的根本原因和100%能解決問題的方法。在這里先作幾點猜測:

  1. 網絡連接問題。既然在開發板上運行系統不會死機,而使用nfs掛載就會死機,那有理由懷疑和網絡連接有關,但是這肯定不是問題發生的根本原因,只是由某個問題導致了兩種不同的現象;

  2. 存儲器問題。可能是Nand Flash出問題,導致內核下載進去時出現了某些錯誤內容。這樣推測的理由是出現問題之后系統變得難以啟動,而且重燒系統之后這個問題就不再出現了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM