C语言编译成DLL文件,给其他程序调用。C语言编译成EXE文件,执行简单功能。HEX文件合并

文章目录

  • 一、简介
  • 二、步骤
    • 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 
#include 

/* 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 
#include 
#include 
#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 
#include 
#include 
#include 
#include 

/**
 * @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 path
    FileNameHandle(argv[2], path[1], 1);  // app path
    FileNameHandle(argv[3], path[2], 1);  // mergeHex path
    FileHandle(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选项卡设置编译后调用批处理脚本,使用起来非常方便.

你可能感兴趣的:(嵌入式开发随笔,c语言,c#,DLL)