C語言編譯成DLL文件,編譯成EXE文件,執(zhí)行簡單功能
一、簡介
在聯(lián)合開發(fā)過程中,用c語言寫好功能函數(shù),給其他上位機(jī)程序調(diào)用。
二、步驟
1. 先編寫c語言文件。用CRC8舉例。crc8_2f.c crc8_2f.h
```c
#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);
}
```
```c
#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 執(zhí)行下面命令:
```bash
gcc -shared crc8_2f.c -o crc8_2f.dll
```
需要安裝gcc編譯器**mingw32**。
3. 給上位機(jī)調(diào)用
(1)C#
```csharp
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);
?
? ? ? ? // 上面已經(jīng)使用了 crc8_2f.dll 文件的絕對路徑,
? ? ? ? // 在此處可以只寫該 dll文件名,但為了保險起見,還是最好寫待調(diào)用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) 易語言
```bash
.版本 2
.DLL命令 read, 整數(shù)型, "crc8_2f.dll", "@CRC8Calculation", 公開, @代表使用__stdcall,否則報錯-堆棧錯誤
? ? .參數(shù) buff, 字節(jié)集, 傳址
? ? .參數(shù) len, 整數(shù)型
```
?三、編譯成EXE
## 1. 編寫一個c文件。 merge_hex.c(例:hex文件合并)
```c
#include <direct.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
?* @brief? 得到文件行
?* @param? path: 文件路徑
?* @retval 文件行數(shù)(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: 目標(biāo)路徑
?* @param? flag:? 1表示遇到'\'需要進(jìn)行增加一個'\'處理, 0表示不需要處理
?* @retval?
?*/
int FileNameHandle(char* ParaPath, char* TargetPath, int flag) {
? ? char* CurrentPath;
? ? int i = 0, j = 0, k = 0;
? ? int PathLevel = 0, PathLast = 0;
? ? // 獲取傳入的參數(shù)路徑有多少個上級目錄,也就是"..\"的個數(shù)
? ? 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);
? ? // 獲取當(dāng)前絕對路徑
? ? if ((CurrentPath = getcwd(NULL, 0)) == NULL) {
? ? ? ? perror("getcwd error");
? ? }
? ? // printf("CurrentPath: %s\n",CurrentPath);
? ? // 當(dāng)前絕對路徑字符串由后往前遍歷,根據(jù)上級目錄個數(shù)PathLevel,去掉多余路徑,得到參數(shù)路徑的絕對路徑
? ? for (i = strlen(CurrentPath) - 1; PathLast < PathLevel; i--) {
? ? ? ? if (CurrentPath[i] == '\\') {
? ? ? ? ? ? PathLast++;
? ? ? ? }
? ? }
? ? // printf("PathLast:%d? i is:%d\n",PathLast,i);
? ? // 將處理后的當(dāng)前絕對路徑,賦值到目標(biāo)路徑的前面
? ? 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);? // 打印參數(shù)傳入的原始路徑
? ? }
? ? fclose(fp3);
? ? free(mergeflie);
? ? return 0;
}
int main(int argc, char** argv) {
? ? char path[3][2048];
? ? if (argc < 4) {
? ? ? ? printf("error!\n");
? ? ? ? printf("參數(shù)缺失\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. 編譯文件
```bash
gcc merge_hex.c -o mergeHEX2.exe
```
## 3. 合并腳本.bat
```bash
echo off
mergeHEX2.exe .\BOOT.hex .\MCU.hex .\boot_app.hex
pause
```
用于合并hex文件的小工具,通過批處理腳本調(diào)用傳參,在MDK中,可以在魔術(shù)棒的User選項(xiàng)卡設(shè)置編譯后調(diào)用批處理腳本,使用起來非常方便.