国民技术N32G430开发笔记(15)- IAP升级 树莓派串口发送数据

news2024/9/30 11:35:53

IAP升级 树莓派串口发送数据

1、树莓派接入usb转串口模块后,会生成/dev/ttyUSB0节点,因为树莓派内核已经编译usb_serial以及各模块的驱动。
我们直接对ttyUSB0节点编程即可。
2、协议同上一节
cmd + data_lenght + data0 + …+ datax + checksum
1、获取版本号 0x01 0x02 0x00 0x00 checksum
2、升级
1、进入升级模式 0x02 0x02 0x00 0x00 checksum
2、升级文件大小 0x03 0x04 0x00 0x00 0x00 0x00 checksum
3、数据包发送 0x04 0x80 0x00 0x00 0x00 0x00 … checksum
4、数据包发送完成 0x05 0x02 0x00 0x00 checksum

checksum采用crc16的检验方法。

3、升级过程:
1、发送升级模式命令。
2、发送文件大小命令
3、循环发送Application.bin的升级包,每包数据head+64个数据+checksum。
4、发送升级完成命令。
4、代码解析如下:
在这里插入图片描述
在build目录执行 cmake …;make 即可编译出uartiap。

CMakeLists.txt

cmake_minimum_required(VERSION 3.18.4)
project (uartIap)

aux_source_directory(. C_SOURCES)
aux_source_directory(./UartIap C_SOURCES_UART)

include_directories(./UartIap)

add_executable(${PROJECT_NAME} ${C_SOURCES} ${C_SOURCES_UART})
target_link_libraries(${PROJECT_NAME} pthread)

n32g430_iap.c

#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
#include "uart.h"

#define APPLICATION_PATH                "Application.bin"
#define UPGRADE_DATA_PACKAGES_LENGHT    0x40
#define UPGRADE_PACKAGES_LENGHT         0x40 + 0x04

typedef enum{

    MI_FALSE  =   0,
    MI_TRUE   =   1,

}MI_BOOL;

typedef unsigned char   MI_U8;
typedef unsigned short  MI_U16;

MI_U8 get_ver_cmd[6]            = {0x01,0x02,0x00,0x00,0x00,0x00};
MI_U8 update_cmd[6]             = {0x02,0x02,0x00,0x00,0x00,0x00};
MI_U8 file_size_cmd[8]          = {0x03,0x04,0x00,0x00,0x00,0x00,0x00,0x00};
MI_U8 file_package[UPGRADE_PACKAGES_LENGHT]         = {0x04,UPGRADE_DATA_PACKAGES_LENGHT};
MI_U8 update_complete_cmd[6]    = {0x05,0x02,0x00,0x00};
MI_U16 w_num = 0;

static MI_U8 isRunning = 0;
char r_data[256] = {0};
sem_t sem;

static MI_BOOL get_update_file_size(char * file_path,size_t *size)
{
    FILE *file;

    file = fopen(file_path,"rb");

    if (!file)
    {
        perror("get_update_file_size fopen error\n");
        return MI_FALSE;
    }
    fseek(file, 0L, SEEK_END);

    *size = ftell(file);

    fclose(file);
    return MI_TRUE;
}

static MI_U16 CRC16(MI_U8 * buf, MI_U16 len)
{
	MI_U16 i;
	MI_U16 crc = 0xffff;
 
	if (len == 0) {
		len = 1;
	}
	while (len--) {
        
		crc ^= *buf;
		for (i = 0; i<8; i++) 
		{            
			if (crc & 1) {               
				crc >>= 1;        
				crc ^= 0xA001;            
			}      
			else {               
				crc >>= 1;            
			}       
		}     
		buf++;
	}
	return(crc);
}

static MI_BOOL compare(MI_U8 *des,MI_U8 *src,int len)
{
    while (len--)
    {
        if (*des != *src)
        {
            return MI_FALSE;
        }

        des++;
        src++;
    }

    return MI_TRUE;
}

static void send_get_version_cmd(int fd)
{
    int len = sizeof(get_ver_cmd);
    int crc = CRC16(get_ver_cmd,len-2);
    get_ver_cmd[len-2] = crc & 0x00ff;
    get_ver_cmd[len-1] = ((crc >> 8) & 0x00ff);
    serialWrite(fd,get_ver_cmd,sizeof(get_ver_cmd));
}

static void send_enter_update_cmd(int fd)
{
    int len = sizeof(update_cmd);
    int crc = CRC16(update_cmd,len-2);
    update_cmd[len-2] = crc & 0x00ff;
    update_cmd[len-1] = ((crc >> 8) & 0x00ff);
    serialWrite(fd,update_cmd,sizeof(update_cmd));
}

static MI_BOOL send_update_file_size_cmd(int fd)
{
    int len = sizeof(file_size_cmd);
    size_t file_size = 0;
    get_update_file_size(APPLICATION_PATH,&file_size);

    file_size_cmd[2] = (file_size >> 24 & (0xff));
    file_size_cmd[3] = (file_size >> 16 & (0xff));
    file_size_cmd[4] = (file_size >> 8 & (0xff));
    file_size_cmd[5] = (file_size & (0xff));

    int crc = CRC16(file_size_cmd,len-2);
    file_size_cmd[len-2] = crc & 0x00ff;
    file_size_cmd[len-1] = ((crc >> 8) & 0x00ff);

    serialWrite(fd,file_size_cmd,sizeof(file_size_cmd));
    return MI_TRUE;
}

static MI_BOOL send_file_every_package(int fd)
{
    int len = sizeof(file_package);
    FILE *fp;
    size_t file_size;
    int package_num;
    MI_U8 package_buff[UPGRADE_DATA_PACKAGES_LENGHT] = {0};

    fp = fopen(APPLICATION_PATH,"rb");
    if (!fp)
    {
        perror("fopen error\n");
        return MI_FALSE;
    }
    get_update_file_size(APPLICATION_PATH,&file_size);

    if (file_size % UPGRADE_DATA_PACKAGES_LENGHT == 0 )
    {
        package_num = file_size / UPGRADE_DATA_PACKAGES_LENGHT;
    }
    else
    {
        package_num = (file_size / UPGRADE_DATA_PACKAGES_LENGHT) + 1;
    }

    printf("pageage_num == %d\n",package_num);
    while (!feof(fp)/* condition */)
    {
        /* code */
        int r_len = fread(package_buff,1,UPGRADE_DATA_PACKAGES_LENGHT,fp);
        
        // 最后读出来不满128 ,用0xff补全。
        if (r_len != UPGRADE_DATA_PACKAGES_LENGHT)
        {
            for (int i=r_len;i<UPGRADE_DATA_PACKAGES_LENGHT;i++)
            {
                package_buff[i] = 0xff;
            }
        }

        memcpy(&file_package[2],package_buff,sizeof(package_buff));

        int crc = CRC16(file_package,sizeof(file_package)-2);
        file_package[sizeof(file_package)-2] = crc & 0x00ff;
        file_package[sizeof(file_package)-1] = ((crc >> 8) & 0x00ff);


        usleep(30 * 1000);
        w_num++;

        printf("send package process == [%03d]\n", ((w_num * 100)/package_num));

#if DEBUG
        for(int i=0;i< len;i++)
        {
            printf("0x%02x  ",file_package[i]);
            if ((i+1) % 16 == 0)
                printf("\n");
        }
        printf("\n");

#endif
        memset(r_data,0,sizeof(r_data));
        serialWrite(fd,file_package,len);
        sem_wait(&sem);
#if DEBUG
        // for(int i=0;i< len;i++)
        // {
        //     printf("0x%02x  ",r_data[i]);
        //     if ((i+1) % 16 == 0)
        //         printf("\n");
        // }
        // printf("\n");


        // int status = compare(r_data,file_package,20);
        // if (status)
        // {
        //     printf("send_file_every_package and receive cmd success!\n");
        // }
        // else
        // {
        //     perror("send_file_every_package not equal receive cmd\n");
        // }
       
        //printf("read len == %d  w_num == %d \n",len,w_num);
 #endif        
    }
    
    fclose(fp);
    return MI_TRUE;
}

static MI_BOOL send_update_complete_cmd(int fd)
{
    int len = sizeof(update_complete_cmd);
    int crc = CRC16(update_complete_cmd,len-2);
    update_complete_cmd[len-2] = crc & 0x00ff;
    update_complete_cmd[len-1] = ((crc >> 8) & 0x00ff);
    serialWrite(fd,update_complete_cmd,sizeof(update_complete_cmd));

    return MI_TRUE;
}

void *uart_read_thread(void *arg)
{
    int fd = *((int *)arg);
    size_t  size ;        

    sem_wait(&sem);
    while(isRunning)
    {
        size = serialRead(fd,r_data,256); //阻塞方式去读

    #if DEBUG    
        if (size > 0)
        {
            for(int i=0;i<size;i++)
            {
                printf("0x%02x  ",r_data[i]);
            }
            printf("\n");
        }
    #endif    
        sem_post(&sem);
    }

    printf("uart_read_thread exit\n");
    pthread_exit(0);
}

int main(int argc,char *argv[])
{
    int fd = 0;
    int ret;
    char w_data[] = "hello world\n";
    MI_U16 crc = 0;
    MI_BOOL status;
    pthread_t m_read_thread ;
    size_t update_file_size;

    sem_init(&sem, 0, 0);
    fd = serialOpen("/dev/ttyUSB0",115200);

    if (fd > 0)
    {
        printf("open ttyUSB0 ok\n");
    }
    else
    {
        printf("open ttyUSB0 fail\n");
        return -1;
    }

    ret = pthread_create(&m_read_thread,NULL,uart_read_thread,&fd);
    if (ret)
    {
        perror("pthread_create error\n");
        return -1;
    }
    else
    {
        isRunning = 1;
        sem_post(&sem);
    }

    sleep(1);// 获取一下N32G430C8L7的版本号
    
    memset(r_data,0,sizeof(r_data));
    send_get_version_cmd(fd);
    sem_wait(&sem);

    printf("get version == %s\n",r_data);

    memset(r_data,0,sizeof(r_data));
    send_enter_update_cmd(fd);
    sem_wait(&sem);

    status = compare(r_data,update_cmd,sizeof(update_cmd));
    if (status)
    {
        printf("send_enter_update_cmd and receive cmd success!\n");
    }
    else
    {
        perror("send_enter_update_cmd not equal receive cmd\n");
    }

    get_update_file_size(APPLICATION_PATH,&update_file_size);
    printf("get update file size == %ld\n",update_file_size);

    memset(r_data,0,sizeof(r_data));
    send_update_file_size_cmd(fd);
    sem_wait(&sem);

    status = compare(r_data,file_size_cmd,sizeof(file_size_cmd));
    if (status)
    {
        printf("send_update_file_size_cmd and receive cmd success!\n");
    }
    else
    {
        perror("send_update_file_size_cmd not equal receive cmd\n");
    }

    send_file_every_package(fd);

    memset(r_data,0,sizeof(r_data));
    send_update_complete_cmd(fd);
    sem_wait(&sem);

    pthread_cancel(m_read_thread);
    isRunning = 0;

    pthread_join(m_read_thread,NULL);
    serialClose(fd);
    printf("raspberryPi App exit!\n");
}

uart.c

#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <pthread.h>
#include "uart.h"

static speed_t getBaudRate(int baudRate)
{
    switch(baudRate) {
        case 0: return B0;
        case 50: return B50;
        case 75: return B75;
        case 110: return B110;
        case 134: return B134;
        case 150: return B150;
        case 200: return B200;
        case 300: return B300;
        case 600: return B600;
        case 1200: return B1200;
        case 1800: return B1800;
        case 2400: return B2400;
        case 4800: return B4800;
        case 9600: return B9600;
        case 19200: return B19200;
        case 38400: return B38400;
        case 57600: return B57600;
        case 115200: return B115200;
        case 230400: return B230400;
        case 460800: return B460800;
        case 500000: return B500000;
        case 576000: return B576000;
        case 921600: return B921600;
        case 1000000: return B1000000;
        case 1152000: return B1152000;
        case 1500000: return B1500000;
        case 2000000: return B2000000;
        case 2500000: return B2500000;
        case 3000000: return B3000000;
        case 3500000: return B3500000;
        case 4000000: return B4000000;
        default: return -1;
    }
}

static int setParity(int fd,int dataBits,int stopBits,int parity)
{
    struct termios options;
    if (tcgetattr (fd, &options) != 0) {
        printf ("SetupSerial 1");
        return (-1);
    }
    options.c_cflag &= ~CSIZE;
    switch (dataBits) {
        case 7:
            options.c_cflag |= CS7;
            break;
        case 8:
            options.c_cflag |= CS8;
            break;
        default:
            fprintf (stderr, "Unsupported data size\n");
            return (-1);
    }

    switch (parity) {
        case 'n':
        case 'N':
            options.c_cflag &= ~PARENB; /* Clear parity enable */
            options.c_iflag &= ~INPCK;  /* Enable parity checking */
            break;
        case 'o':
        case 'O':
            options.c_cflag |= (PARODD | PARENB);
            options.c_iflag |= INPCK;   /* Disable parity checking */
            break;
        case 'e':
        case 'E':
            options.c_cflag |= PARENB;  /* Enable parity */
            options.c_cflag &= ~PARODD;
            options.c_iflag |= INPCK;   /* Disable parity checking */
            break;
        case 'S':
        case 's':           /*as no parity */
            options.c_cflag &= ~PARENB;
            options.c_cflag &= ~CSTOPB;
            break;
        default:
            fprintf (stderr, "Unsupported parity\n");
            return (-1);
    }
    switch (stopBits) {
        case 1:
            options.c_cflag &= ~CSTOPB;
            break;
        case 2:
            options.c_cflag |= CSTOPB;
            break;
        default:
            fprintf (stderr, "Unsupported stop bits\n");
            return (-1);
    }

    /* Set input parity option */
    if (parity != 'n')
        options.c_iflag |= INPCK;
    tcflush (fd, TCIFLUSH);
    options.c_cc[VTIME] = 0x01;
    options.c_cc[VMIN] =  0xFF; /* Update the options and do it NOW */
    //qd to set raw mode, which is copied from web
    options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
                         | INLCR | IGNCR | ICRNL | IXON);
    options.c_oflag &= ~OPOST;
    options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
    options.c_cflag &= ~(CSIZE | PARENB);
    options.c_cflag |= CS8;

    if (tcsetattr (fd, TCSANOW, &options) != 0) {
        perror ("SetupSerial 3");
        return (-1);
    }

    return 0;
}

int serialOpen(const char *path, int baudRate)
{
    int fd;
    speed_t speed;

    /* Check arguments */
    {
        speed = getBaudRate(baudRate);
        if (speed == -1) {

            printf("get Baud rate error\n");
            return -1;
        }
    }
    {
        fd = open(path, O_RDWR);
        if (fd == -1)
        {
            printf("open serial error =%d\n",fd);
            return -1;
        }
    }
    /* Configure device */
    {
        struct termios cfg;
        if (tcgetattr(fd, &cfg))
        {
            printf("tcgetattr() failed\n");
            close(fd);
            return -1;
        }

        cfmakeraw(&cfg);
        cfsetispeed(&cfg, speed);
        cfsetospeed(&cfg, speed);

        if (tcsetattr(fd, TCSANOW, &cfg))
        {
            printf("tcsetattr() failed\n");
            close(fd);
            return -1;
        }
    }
    setParity(fd,8,1,'N');
    //printf("open Success==%d\n",fd);
    return fd;
}


int serialWrite(int fd,char *writeData,int len)
{
    if (fd > 0){
        write(fd,writeData,len);
    }else{

        printf("[File]=%s[Function]=%s error\n",__FILE__,__FUNCTION__);
        return -1;
    }
    return 0;
}

int serialRead(int fd,char *readData,int len)
{
    size_t size = 0;
    if (fd > 0)
    {
        size = read(fd,readData,len);
    }
    else
    {

        printf("[File]=%s[Function]=%s error\n",__FILE__,__FUNCTION__);
        return -1;
    }
    return size;
}

int serialClose(int fd)
{
    close(fd);
    return 0;
}

uart.h

#ifndef __UART_H__
#define __UART_H__

int serialOpen(const char *path, int baudRate);
int serialWrite(int fd,char *writeData,int len);
int serialRead(int fd,char *readData,int len);
int serialClose(int fd);

#endif

5、视频

屏幕录制2023-05-03 15.39.07

6、代码路径 : https://gitee.com/xiaoguo-tec_0/raspberrypi

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/485597.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AutoDL-GPU租用平台使用(LLM 备用)

网址&#xff1a;AutoDL-品质GPU租用平台-租GPU就上AutoDL 1 打开网址 查看下显卡型号及价格&#xff1a;A100 ( 80 G 显存) 6.68/小时 、4090&#xff08;24G 显存&#xff09;2.68/小时 2 创建实例 1.注册登录后进入控制台&#xff08;页面右上角&#xff09;&#xff0…

08 KVM虚拟机配置-总体介绍

文章目录 08 KVM虚拟机配置-总体介绍8.1 概述8.2 基本格式8.3 配置流程 08 KVM虚拟机配置-总体介绍 8.1 概述 Libvirt工具采用XML格式的文件描述一个虚拟机特征&#xff0c;包括虚拟机名称、CPU、内存、磁盘、网卡、鼠标、键盘等信息。用户可以通过修改配置文件&#xff0c;对…

【应急响应】日志自动提取分析项目ELKLogkitLogonTracerAnolog等

日志自动提取-七牛Logkit&观星应急工具 1、七牛Logkit&#xff1a;(Windows&Linux&Mac等) https://github.com/qiniu/logkit/ 支持的数据源&#xff08;各类日志&#xff0c;各个系统&#xff0c;各个应用等&#xff09; File: 读取文件中的日志数据&#xff0c;包…

第二章 主机规划与磁盘分区

要安装好一部Linux主机并不是那么简单的事情&#xff0c;你必须要针对distributions的特性、服务器软件的能力、未来的升级需求、硬件扩充性需求等等来考虑&#xff0c;还得要知道磁盘分区、文件系统、Linux操作较频繁的目录等等&#xff0c;都得要有一定程度的了解才行。 2.1…

训练CV模型常用的Tips Tricks

训练CV模型常用的Tips & Tricks主要从以下9个方面进行介绍&#xff1a; 图像增强更好的模型学习率和scheduler优化器正则化手段标签平滑知识蒸馏伪标签错误分析 1. 图像增强 以下列出了许多增强方式&#xff0c;有的甚至没见过&#xff0c;但是也不是每一种增强方式都是…

极化码的入门与探索

文章目录 极化码的基础先验知识二进制输入离散无记忆信道模型(Binary-input Discreten Memoryless Channel, B-DMC)二进制离散输入信道的ML判决和错误率B-DMC相关参数的定义和理解 两信道极化N信道极化的解释信道极化分解的蝶形结构补充&#xff1a;生成矩阵的结构 极化码的基础…

Python算法设计 - 快速排序

目录 一、快速排序二、Python算法实现 一、快速排序 快速排序的概念相信大家都能理解&#xff0c;下面这个算法是基于同样想法的另一种算法&#xff0c;其中利用到了分区。如果实施正确&#xff0c;这是一种非常有效的算法&#xff0c;在预期的O(n.log n) 时间内运行&#xff…

性能测试场景分析并设计?超细案例讲解,看这篇就够了

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能测试场景&…

1.1 基于B/S 结构的 Web 应用

文章目录 1.1 基于B/S 结构的 Web 应用1.2 JDK安装与配置1.3 服务器Tomcat下载与安装1.4 Eclipse安装与使用1.4.1 Eclipse 下载及创建Dynamic Web Project1.4.2 Eclipse 中的编码问题1.4.3 将Tomcat和Eclipse相关联1.4.4 Eclipse 自动部署项目到 Tomcat 的 webapps 目录 1.5 My…

ChatGLM-6B模型微调实战(以 ADGEN (广告生成) 数据集为例)

1 介绍 对于 ChatGLM-6B 模型基于 P-Tuning v2 的微调。P-Tuning v2 将需要微调的参数量减少到原来的 0.1%&#xff0c;再通过模型量化、Gradient Checkpoint 等方法&#xff0c;差不多需要 7GB或则8GB 显存即可运行。 2 环境 2.1 python 环境 conda create -n py310_cha…

go 打包文件夹成zip文件

go 打包文件夹成zip文件 代码有些乱&#xff0c;找不到合适的例子&#xff0c;和优雅的代码 当前代码打包文件是在 需要打包的目录下&#xff0c;测试的时候注意文件翻倍容量 writer, err : zzip.CreateHeader(header) //这里创建文件时注意不要用完整路径 zip中会生产完整路径…

【51单片机】蜂鸣器

&#x1f38a;专栏【51单片机】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【Love Story】 大一同学小吉&#xff0c;欢迎并且感谢大家指出我的问题&#x1f970; &#x1f354;效果 &#xff08;注意听声音哦&#xff09; 按…

Blob File

文章目录 学习链接Blob创建演示 分片演示 Fileinput手动拖拽fetch 从后端获取流前端代码后端代码 window.showOpenFilePicker Filereader示例1示例2 ArrayBuffer创建bufferTypedArray读写bufferDataView读写buffer与Blob对比 Blob Url & DataUrl示例1示例2 学习链接 Blog …

WIFI密码hacking学习

1 wifite sudo -i 切换到root终端&#xff0c;执行wifite CtrlC 停止WIFI列表扫描 这里选择爆破目标1&#xff0c;他会先监听客户端和wifi的连接的数据包&#xff0c;然后用wordlist-probable.txt里面的字典进行爆破 区别 WPS 是 no 的和yes no会自动化爆破 这种模式默认下…

软件测试行业前景怎么样

软件测试工程师工作好找&#xff0c;但是企业有时却很难招聘到合适的软件测试工程师&#xff0c;这是因为现在企业需要的是自动化测试人才和测试开发人才&#xff01;前些年的手动测试员早已不能满足企业现在的发展需求。 随着人工智能时代的到来&#xff0c;IT行业受到了越来…

从‘孔乙己长衫’现象看社会不公

孔乙已是鲁迅笔下人物&#xff0c;穷困流倒还穿着象征读书人的长衫&#xff0c;迁腐、麻木。最近&#xff0c;大家自我调佩是“当代孔乙己”&#xff0c;学历成为思想负担&#xff0c;找工作时高不成低不就。 认识孔乙己 孔乙己是清朝末年的小贩&#xff0c;生活在贫苦的阶层…

ubuntu22.04安装与配置

目录 一、环境及下载 iso下载 VM配置 二、虚拟机与环境配置 虚拟机开始后的配置 一些工具配置 参考&#xff1a; VMware Workstation Pro 文档 一、环境及下载 iso下载 Download Ubuntu Desktop | Download | Ubuntu 新出了23但是偶数年份稳定支持&#xff0c;所以我…

openai接口调用-如何接入openai获取 api key

openai api key获取 获取 OpenAI API Key 非常简单&#xff0c;您只需要按照以下步骤进行操作: 创建 OpenAI 账户。如果您还没有 OpenAI 账户&#xff0c;请访问 OpenAI 官网&#xff08;http://openai.com/signup&#xff09;并创建一个帐户。登录您的 OpenAI 账户。使用您的…

docker安装ES、kibana和IK分词器

拉取镜像 docker pull elasticsearch:7.4.2 docker pull kibana:7.4.2创建存储数据的目录 mkdir -p /home/lab1018/docker_volume/elasticsearch/config mkdir -p /home/lab1018/docker_volume/elasticsearch/data mkdir -p /home/lab1018/docker_volume/elasticsearch/plugi…

C++-----动态规划

目录 一、动态规划的基本思想 二、设计动态规划法的步骤 三、动态规划问题的特征 4.1 矩阵连乘积问题 4.1.1 分析最优解的结构 4.1.2 建立递归关系 4.1.3 计算最优值 4.1.3 计算最优值 4.1.3 构造最优解 4.2 动态规划算法的基本要素 4.2.1 最优子结构 4.2.2 重叠子问题 …