文章目录
- 一、简介
- 二、步骤
- 1. 先编写c语言文件。用CRC8举例。crc8_2f.c crc8_2f.h
- 2. 编译成DLL文件
- 3. 给上位机调用
- (1)C#
- (2) 易语言
- 三、编译成EXE
- 1. 编写一个c文件。 merge_hex.c(例:hex文件合并)
- 2. 编译文件
- 3. 合并脚本.bat
一、简介
在联合开发过程中,用c语言写好功能函数,给其他上位机程序调用。
二、步骤
1. 先编写c语言文件。用CRC8举例。crc8_2f.c crc8_2f.h
#include <stdint.h>
#include <stdio.h>/* Constant array CRC8 */
static const uint8_t LIB_Crc8Table1[16] = {0x42u, 0x6du, 0x1cu, 0x33u, 0xfeu, 0xd1u, 0xa0u, 0x8fu,0x15u, 0x3au, 0x4bu, 0x64u, 0xa9u, 0x86u, 0xf7u, 0xd8u
};static const uint8_t LIB_Crc8Table2[16] = {0x42u, 0xecu, 0x31u, 0x9fu, 0xa4u, 0x0au, 0xd7u, 0x79u,0xa1u, 0x0fu, 0xd2u, 0x7cu, 0x47u, 0xe9u, 0x34u, 0x9au
};/*** @brief This function calculates a CRC8 over the data buffer* @param LIB_TempInputCrc8_cp[in]: pointer to the input data* @param LIB_TempLengthCrc8_u16[in]: Length of the input data* @return Calculated CRC8* @details Local variables* Loop over all byte* Execute CRC algorithm* Return inverted result* @ReqKey MOD_LIB-64, MOD_LIB-65*/
uint8_t CRC8Calculation(const uint8_t* data, const uint16_t len) {/* Local Variables */uint8_t LIB_TempCrc8_u8 = 0xFFu;uint16_t LIB_TempIndexCrc8_u16;/* Loop over all bytes */for (LIB_TempIndexCrc8_u16 = 0u;LIB_TempIndexCrc8_u16 < len;LIB_TempIndexCrc8_u16++) {/* CRC Algorithm */LIB_TempCrc8_u8 = data[LIB_TempIndexCrc8_u16] ^ LIB_TempCrc8_u8;LIB_TempCrc8_u8 = (LIB_Crc8Table1[LIB_TempCrc8_u8 & 0x0Fu]) ^(LIB_Crc8Table2[LIB_TempCrc8_u8 >> 4u]);}return (LIB_TempCrc8_u8 ^ 0xFF);
}
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#ifndef CRC8_2F_H_
#define CRC8_2F_H_uint8_t CRC8Calculation(void* data, uint16_t size);
#endif
2. 编译成DLL文件
cmd 执行下面命令:
gcc -shared crc8_2f.c -o crc8_2f.dll
需要安装gcc编译器mingw32。
3. 给上位机调用
(1)C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;namespace CallTheDll01
{class Program{// 在此处使用 crc8_2f.dll 文件的绝对路径[DllImport(@"D:\crc8_2f.dll",CallingConvention=CallingConvention.Cdecl)]public static extern byte CRC8Calculation(void* data, ushort size);// 上面已经使用了 crc8_2f.dll 文件的绝对路径,// 在此处可以只写该 dll文件名,但为了保险起见,还是最好写待调用dll文件的绝对路径名[DllImport("crc8_2f.dll", EntryPoint = "CRC8Calculation",CallingConvention =CallingConvention.Cdecl)]public static extern byte CRC8_Cal(void* data, ushort size);static void Main(string[] args){byte[] data = new byte[] {3, 32, 35, 6, 12, 21, 122};Console.WriteLine("{0}", CRC8Calculation(data, 7));Console.WriteLine("{0}", CRC8_Cal(data, 7));Console.ReadKey();}}
(2) 易语言
.版本 2.DLL命令 read, 整数型, "crc8_2f.dll", "@CRC8Calculation", 公开, @代表使用__stdcall,否则报错-堆栈错误.参数 buff, 字节集, 传址.参数 len, 整数型
三、编译成EXE
1. 编写一个c文件。 merge_hex.c(例:hex文件合并)
#include <direct.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>/*** @brief 得到文件行* @param path: 文件路径* @retval 文件行数(hex文件每行44列)*/
int GetFileLIine(char* path) {int i = 0;// char j = 0;char str[45];FILE* fp;// printf("Path: %s \n",path);if ((fp = fopen(path, "r")) == NULL)printf("fail to open the file path:%s! \n", path);while (fgets(str, 45, fp)) {i++;}fclose(fp);return i;
}/*** @brief 路径处理* @param ParaPath: * @param TargetPath: 目标路径* @param flag: 1表示遇到'\'需要进行增加一个'\'处理, 0表示不需要处理* @retval */
int FileNameHandle(char* ParaPath, char* TargetPath, int flag) {char* CurrentPath;int i = 0, j = 0, k = 0;int PathLevel = 0, PathLast = 0;// 获取传入的参数路径有多少个上级目录,也就是"..\"的个数for (i = 0; (ParaPath[i] == '\\') || (ParaPath[i] == '.'); i++) {if ((ParaPath[i] == '.') && (ParaPath[i - 1] == '.')) {PathLevel++;}}// printf("ParaPath:%s\n",ParaPath);// printf("PathLevel:%d i is:%d\n",PathLevel,i);// 获取当前绝对路径if ((CurrentPath = getcwd(NULL, 0)) == NULL) {perror("getcwd error");}// printf("CurrentPath: %s\n",CurrentPath);// 当前绝对路径字符串由后往前遍历,根据上级目录个数PathLevel,去掉多余路径,得到参数路径的绝对路径for (i = strlen(CurrentPath) - 1; PathLast < PathLevel; i--) {if (CurrentPath[i] == '\\') {PathLast++;}}// printf("PathLast:%d i is:%d\n",PathLast,i);// 将处理后的当前绝对路径,赋值到目标路径的前面for (j = 0, k = 0; j <= i; j++) {TargetPath[k++] = CurrentPath[j];if (flag)if (CurrentPath[j] == '\\')TargetPath[k++] = '\\';}TargetPath[k] = '\0';// printf("TargetPath:%s\n",TargetPath);for (i = 0; ParaPath[i] != '\0'; i++) {if (ParaPath[i] != '.') {TargetPath[k++] = ParaPath[i];if (flag)if (ParaPath[i] == '\\')TargetPath[k++] = ParaPath[i];}if ((ParaPath[i] == '.') && ((ParaPath[i - 1] != '.') && (ParaPath[i + 1] != '.')))TargetPath[k++] = ParaPath[i];}TargetPath[k] = '\0';// printf("TargetPath:%s\n",TargetPath);free(CurrentPath);return k;
}int FileHandle(char* path1, char* path2, char* path3, char* path4) {FILE* fp1;FILE* fp2;FILE* fp3;char str[45];char* mergeflie;int i = 0;int k1 = 0, k2 = 0;char CurrentPath[2048];FileNameHandle(path4, CurrentPath, 0);k1 = GetFileLIine(path1);k2 = GetFileLIine(path2);mergeflie = (char*)malloc((k1 + k2) * 45);mergeflie[0] = '\0';if ((fp1 = fopen(path1, "r")) == NULL)printf("fail to open the file path:%s! \n", path1);for (i = 0; i < k1 - 2; i++) {fgets(str, 45, fp1);strcat(mergeflie, str);}fclose(fp1);// printf("Path: %s,line number:%d \n",path1,i);if ((fp2 = fopen(path2, "r")) == NULL)printf("fail to open the file path:%s! \n", path2);// printf("k2-1:%d\n",k2-1);fgets(str, 45, fp2);for (i = 0; i < k2 - 1; i++) {fgets(str, 45, fp2);strcat(mergeflie, str);}fclose(fp2);i = strlen(mergeflie);mergeflie[i] = '\n';if ((fp3 = fopen(path3, "w")) == NULL)printf("fail to open the file path:%s! \n", path3);else {fwrite(mergeflie, strlen(mergeflie), 1, fp3);printf("creat %s success!\n", CurrentPath); // 打印参数传入的原始路径}fclose(fp3);free(mergeflie);return 0;
}int main(int argc, char** argv) {char path[3][2048];if (argc < 4) {printf("error!\n");printf("参数缺失\n");return -1;}FileNameHandle(argv[1], path[0], 1); // bootloader pathFileNameHandle(argv[2], path[1], 1); // app pathFileNameHandle(argv[3], path[2], 1); // mergeHex pathFileHandle(path[0], path[1], path[2], argv[3]);return 0;
}
2. 编译文件
gcc merge_hex.c -o mergeHEX2.exe
3. 合并脚本.bat
echo off
mergeHEX2.exe .\BOOT.hex .\MCU.hex .\boot_app.hex
pause
用于合并hex文件的小工具,通过批处理脚本调用传参,在MDK中,可以在魔术棒的User选项卡设置编译后调用批处理脚本,使用起来非常方便.