
设计资料分享之-电流计日常软、硬件学习中的资料分享、记录欢迎共同探讨。仅分享主要设计思路、框架、要点、问题探讨等基础知识、单片机 外设开发等可在评论区讨论或者在网盘中获取相关资料。硬件原理图、PCB、软件代码全部分享在网盘中。有错误或可以优化的地方欢迎指出。上位机曲线转换工具下载 链接-百度网盘链接:https://pan.baidu.com/s/1_EbFYPEiGTMo-molvNCuMg?pwdjgst提取码: jgst资料下载链接-百度网盘链接: https://pan.baidu.com/s/12BANguy2kL2D4k3yZG39sw?pwdi2qy提取码: i2qy文章目录目录设计资料分享之-电流计文章目录七、软件功能模块7.1 电流校准7.2 通信协议7.3 flash分配总结七、软件功能模块7.1 电流校准回顾前面介绍的电流计算方式const double CURRENT::lsb_voltage 0.5f * 5.14f * 1000000.0 / 64.0 / 8388607.0; double lsb_current_ma lsb_voltage / shunt_resistor; float cur_current lsb_current_ma * read_adc_only();VREF理论上不是完全等于5.14V与电压基准芯片精度、分压电阻精度有关假设实际VREFk1*5.14Vk1是常数采样电阻阻值是我们根据实际电阻设定的如采样电阻阻值位20mΩ我们设定shunt_resistor20实际采样电阻同样由精度误差假如shunt_resistork2*20不考虑温漂k2是常数ADC芯片读出来的值与实际值应该也有一定误差在两个很相近的点之间可近似认为是成线性关系即实际值k3*读出值k4k3和k4均是常数。那么可得cur_currentk1*k3/k2*lsb_current_ma *read_adc_only() k1*k4/k2k1、k2、k3、k4均为常数因此得cur_currenta*lsb_current_ma *read_adc_only() ba、b均为常数。如下左图如果不做校准我们认为读取值就是实际值。实际上有一定误差假如我们可以得到如右图y1、y2、y3、y4直线的表达式那么可以根据读取值计算实际值。明显如果我们知道读取值与实际值对应的坐标点越多计算出来的实际值越准确。定义一个结构体struct CALI_TABLE { float sample_current; float real_current; };用来记录读取值和实际值的坐标点。我们定义10个数组储存这些坐标点定义坐标点的有效点数uint32_t valiable_num; //有效校准数据数量 CALI_TABLE cali_table[CALI_TABLE_SIZE];校准的过程只需要保存读取值对应实际值实际值需要通过高精度电流表获取我们近似的认为高精度电流表读取的是实际电流不过理论上也是有一定误差的点即可保存坐标点函数如下按照读取值的顺序更新坐标点的数组void CALIBRATE::add_current_to_table(float sample_current, float real_current) { if(valiable_num CALI_TABLE_SIZE) { // 找到合适的插入位置按sample_current升序排列 int insert_pos valiable_num; for(int i 0; i valiable_num; i) { if(cali_table[i].sample_current sample_current) { insert_pos i; break; } } // 移动现有数据为新数据腾出空间 for(int i valiable_num; i insert_pos; i--) { cali_table[i] cali_table[i-1]; } // 插入新数据 cali_table[insert_pos].sample_current sample_current; cali_table[insert_pos].real_current real_current; valiable_num; } }再根据上述说的读取值与实际值对应关系利用读取到的电流可以计算实际电流值float CALIBRATE::calculate_current(float sample_current) { // 确保valiable_num不超过CALI_TABLE_SIZE if(valiable_num CALI_TABLE_SIZE) { valiable_num CALI_TABLE_SIZE; } if(valiable_num 2) { if(valiable_num 1 cali_table[0].real_current 0) { return sample_current - cali_table[0].sample_current; } return sample_current; } // 找到sample_current所在的位置 int pos 0; for(pos 0; pos valiable_num - 1; pos) { if(cali_table[pos].sample_current sample_current sample_current cali_table[pos1].sample_current) { break; } } // 确保pos不超过valiable_num - 2 if(pos valiable_num - 1) { pos valiable_num - 2; } // 进行线性插值 float x0 cali_table[pos].sample_current; float y0 cali_table[pos].real_current; float x1 cali_table[pos1].sample_current; float y1 cali_table[pos1].real_current; return (y0 (sample_current - x0) * (y1 - y0) / (x1 - x0)); }7.2 通信协议通信协议规定一帧数据由帧头、数据段、帧尾组成。帧头由以下几部分组成// 帧头 struct frame_header_t { uint8_t sync_byte1; // 同步字节1 uint8_t sync_byte2; // 同步字节2 uint8_t frame_type; // 帧类型 uint8_t frame_id; // 命令类型 uint16_t frame_length; // 帧长度(不包括帧头和帧尾) uint8_t reswrved[2]; // 预留 };同步字节1和同步字节2规定固定为0xAA、0x55帧尾由以下几部分组成// 帧尾 struct frame_tail_t { uint16_t crc16; // CRC16校验 uint8_t end_byte1; // 结束字节 (0x0D) uint8_t end_byte2; // 结束字节 (0x0A) };结束字节1和结束字节2规定固定位0x0D、0x0A电流数据上传的数据段规定如下/*** 实时电流数据帧数据 ***/ struct current_data_t { uint32_t time; // 时间戳 float current; // 电流值 };上传测试时间和电流值平均值、最大值、最小值由上位机工具统计。MCU升级需要包含响应是否允许升级、数据包确认和下一包数据序号、文件传输结果确认结构体如下// 文件发送响应帧数据 struct file_send_response_t { uint8_t file_allowed; // 是否允许文件发送 uint8_t reserved[3]; // 保留字节 }; // 数据包确认帧数据 struct data_ack_t { uint32_t packet_num; // 确认的包序号 uint32_t next_packet_num;// 请求下一包序号 uint8_t reserved[4]; // 保留字节 }; // 文件发送结果帧数据 struct file_send_result_t { uint8_t file_result; // 文件发送结果 uint8_t reserved[3]; // 保留字节 };而上位机升级工具需要包含升级请求包含文件信息、固件数据包// 文件发送请求帧数据 struct file_send_require_t { uint32_t total_file_size;// 总文件大小 uint32_t total_packets; // 包数量 uint16_t packet_size; // 单包大小128字节和1024字节 uint16_t file_crc16; // 文件校验码 }; // 数据包帧数据 struct data_packet_t { uint32_t packet_num; // 包序号 uint16_t data_length; // 数据长度 uint8_t reserve[2]; // 保留字节 //uint8_t data[]; // 数据内容(柔性数组) };7.3 flash分配STM32F103C8T6共64k字节FLASH属于中容量产品共64页每页1k字节。固件升级采用双备份方式能保证在固件升级过程中如果发生失败还能在继续运行升级之前的固件不会导致设备不工作。因此储存空间要包含三个程序分别为BOOTLOADER程序APP程序备份程序。另外还需要一块空间保存固件升级标志、硬件版本、校准参数、分流器阻值等。因此64k空间分为以下4块页起始地址结束地址大小字节用途0-80x0800 00000x0800 23FF9kBOOTLOADER程序9-350x0800 24000x0800 8FFF27kAPP程序36-630x0800 90000x0800 FBFF27k备份程序640x0800 FC000x0800 FFFF1k保存参数保存参数的1k起始地址0x0800 FC00区域具体分配如下地址偏移大小字节符号说明01upgrade_flag0x01需要升级其他不需要升级11reserve预留12crc_16固件的CRC16校验44file_size固件文件大小84shunt_resistor采样电阻阻值单位mΩ124valiable_num有效校准数据数量168*10cali_table【10】校准坐标点总结例如以上就是今天要讲的内容本文分享了电流校准、通信协议、flash空间分配内容下期继续~