这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【分享开发笔记,赚取电动螺丝刀】MAX78000开发板读取摄像头后,使用串口通讯

共1条 1/1 1 跳转至

【分享开发笔记,赚取电动螺丝刀】MAX78000开发板读取摄像头后,使用串口通讯,上位机显示图像

助工
2025-11-04 15:54:10     打赏

上一次使用MAX78000开发板读取摄像头后,使用TFT屏幕显示。虽然成功显示在TFT屏幕上了,但是面包板使用起来还是不够方便,屏幕刷新慢,自己也不确定是TFT屏幕慢?还是MAX78000开发板读取摄像头慢?最重要一点是MAX78000开发板读取到的摄像头的图像最终是想实现机器学习的训练的,所以有对图片保存的需要,于是就有想把摄像头读取到的图片上传给电脑,进行保存和展示。

image.png

MAX7800FEATHER开发板上集成了很多传感器,但是板子上却没有wifi、蓝牙或是网口等通讯功能,与上位机的通讯只能通过串口来完成。在学习美信官方提供的例程时发现“MaximSDK\Examples\MAX78000\CameraIF\pc_utility”这样一个文件夹,使用python写的一个上位机的例程,python也算略懂,于是开始学习这个例程的上位机部分。

第一步:串口初始化。这个开发板的串口还是挺强劲的,使用了921600波特率,换算下来,每秒大约能传输 92160 字节(约 90 KB/s)。一张图片,使用240*240的分辨率,RGB565方式编码,那么每传递一帧图片需要1.25秒,速度还是慢啊!

#define CON_BAUD 115200 * 8 // UART baudrate used for sending data to PC, use max 921600 for serial stream
// Initialize DMA for camera interface
	MXC_DMA_Init();
	dma_channel = MXC_DMA_AcquireChannel();

	mxc_uart_regs_t *ConsoleUart = MXC_UART_GET_UART(CONSOLE_UART);

	if ((ret = MXC_UART_Init(ConsoleUart, CON_BAUD, MXC_UART_IBRO_CLK))
			!= E_NO_ERROR) {
		return ret;
	}

第二步:摄像头初始化。下位机我将例程的代码做了精简。基本流程为 DMA初始化——I2C初始化——摄像头初始化——摄像头启动。这里使用了240X240的分辨率,图像使用RGB565编码。

int main(void) {
	int ret = 0;
	int slaveAddress;
	int id;
	int dma_channel;
	/* Enable cache */
	MXC_ICC_Enable(MXC_ICC0);

	/* Set system clock to 100 MHz */
	MXC_SYS_Clock_Select(MXC_SYS_CLOCK_IPO);
	SystemCoreClockUpdate();

// Initialize DMA for camera interface
	MXC_DMA_Init();
	dma_channel = MXC_DMA_AcquireChannel();

	mxc_uart_regs_t *ConsoleUart = MXC_UART_GET_UART(CONSOLE_UART);

	if ((ret = MXC_UART_Init(ConsoleUart, CON_BAUD, MXC_UART_IBRO_CLK))
			!= E_NO_ERROR) {
		return ret;
	}

// Initialize the camera driver.
	camera_init(CAMERA_FREQ);
	printf("\n\nCamera Example\n");

	slaveAddress = camera_get_slave_address();
	printf("Camera I2C slave address: %02x\n", slaveAddress);

// Obtain the manufacturer ID of the camera.
	ret = camera_get_manufacture_id(&id);

	if (ret != STATUS_OK) {
		printf("Error returned from reading camera id. Error %d\n", ret);
		return -1;
	}

	printf("Camera ID detected: %04x\n", id);

// Setup the camera image dimensions, pixel format and data acquiring details.

	ret = camera_setup(IMAGE_XRES, IMAGE_YRES, PIXFORMAT_RGB565, FIFO_FOUR_BYTE,
			STREAMING_DMA, dma_channel); // RGB565 stream
//    ret = camera_setup(IMAGE_XRES, IMAGE_YRES, PIXFORMAT_GRAYSCALE, FIFO_FOUR_BYTE, STREAMING_DMA,dma_channel); // �Ҷ�ͼ stream

	if (ret != STATUS_OK) {
		printf("Error returned from setting up camera. Error %d\n", ret);
		return -1;
	}

	MXC_Delay(SEC(1));
	camera_write_reg(0x11, 0xE); // can be set to 0xB in release mode ( -o2 )

// Start capturing a first camera image frame.
	printf("Starting\n");
	camera_start_capture_image();

	while (1) {
		{
			// Process the image, send it through the UART console.
			process_img();
			// Prepare for another frame capture.
			LED_Toggle(LED_GREEN);
			camera_start_capture_image();
		}
	}

	return ret;
}

第三步:从DMA读取摄像头采集数据,上送串口。

// 从DMA中读取图片,写入内存
void read_img_fromdma(uint32_t w, uint32_t h, uint8_t *imgdata) {
	uint8_t *data = NULL;
// Get image line by line
	for (int i = 0; i < h; i++) {
// Wait until camera streaming buffer is full
		while ((data = get_camera_stream_buffer()) == NULL) {
			if (camera_is_image_rcv()) {
				break;
			}
		}
		for (int j = 0; j < w * 2; j++) {
			imgdata[i * w * 2 + j] = data[j];
		}
// Release stream buffer
		release_camera_stream_buffer();
	}
}

void process_img(void) {
    uint8_t *raw;
    uint32_t imgLen;
    uint32_t w, h;
// Get the details of the image from the camera driver.
    camera_get_image(&raw, &imgLen, &w, &h);
    uint8_t *imgdata = (uint8_t*) malloc(imgLen);		//使用灰度图 尺寸减半 动态申请内存
    utils_stream_img_to_pc_init(raw, imgLen, w, h, camera_get_pixel_format());
    read_img_fromdma(w, h, imgdata);	//从DMA中读取图片信息,并转换为灰度图,写入imgdata

    utils_stream_image_row_to_pc(imgdata, w * h * 2);
    free(imgdata);
    stream_stat_t *stat = get_camera_stream_statistic();

    if (stat->overflow_count > 0) {
	LED_On(LED_RED); // Turn on red LED if overflow detected
	while (1) {
		}
    }
}

摄像头每次采集到一帧图片后,就将图片数据写到DMA缓存,代码动态申请一段内存,然后将图片信息从DMA区读取到内存里,最后通过串口发送出去。

第四步:上位机。在上位机中手工指定了串口号,波特率选择与下位机相同的921600。其余无改动。上位机的基本思路为:打开串口监听——收到串口数据信息(格式、长度)——接收串口数据——接收完成后保存图片文件——通过OPENCV展示保存了的图片。

comport  = "COM5"
#   # Setup the default baudrate.
baudRate = 921600  # 115200
while True:
    if ( comManager.find_sync() == 1 ):
       print ("\n\n***Sync word found***", flush=True)
       print ("Reading image bytes, please wait...", flush=True)

       # width
       arr = comManager.read(2)
       w = arr[0]*256 + arr[1]
       # height
       arr = comManager.read(2)
       h = arr[0]*256 + arr[1]

       pixelformat_len = comManager.read(1)
       pixelformat = comManager.read(pixelformat_len[0])

       arr = comManager.read(4)
       imageLen = arr[0]*256*256*256 + arr[1]*256*256 + arr[2]*256 + arr[3]

       print ("image Len: %d" % imageLen, flush=True);
       print('Image format is ' + pixelformat.decode('ASCII'))
       if ( imageLen > 0 ):
          image = bytearray()
          startTime = time.time();
          timeout = 0
          while (imageLen != len(image)):
             image += comManager.read(imageLen-len(image))
             print ("  Total Read Len:%d bytes" % len(image), flush=True)
             # check timeout
             if ( time.time() > (startTime + READ_TIMEOUT)):
                print("Test Failed: Timeout\n", flush=True);
                timeout = 1
                break

          if (timeout == 1):
             continue

          print ("All image data read", flush=True);
          imgConverter.convert(image, "Image.png", w, h, pixelformat.decode('ASCII'))

          image = cv2.imread("image.png")
          cv2.imshow(" ", image)
          cv2.waitKey(1)
          #exit(0)

效果演示

2.jpg

源码:CameraIF串口上送PC显示.zip



共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]