作为一名嵌入式工程师,在学习和工作中肯定会遇到很多相同的程序问题,这时候我们就需要把一下自己的一些积累的代码,copy过来直接拿来用或者简单拿来修改修改使用,本文将介绍几个实用的嵌入式C程序示例,并提供相应的代码解析,帮助读者更好地理解和应用这些示例。 代码以实用和帮助理解一些现象为主,如有缺陷,欢迎指出。
1. 日志时间的写入
下面程序实现:将当前的时间写入到time.txt的文件中,如果ctrl+c退出之后,在再次执行支持断点续写。在一些日志文件的写入时,可以选择在后面填写当前的时间。
#include <stdio.h>
#include <string.h>
#include <time.h>
#define PRINT_ERR(errmsg) \
do { \
perror(errmsg); \
printf("%s:%s:%d\n",__FILE__,__func__,__LINE__);\
return -1; \
} while (0)
int get_file_line(FILE* fp)
{
int line=0;
char s[30];
// 循环读文件
while (fgets(s, 30, fp) != NULL) {
if (s[strlen(s) - 1] == '\n')
line++;
}
return line;
}
int main(int argc, const char* argv[])
{
time_t ts, ots;
struct tm* tm;
char tim[50] = { 0 };
FILE* fp;
int line = 0;
if ((fp = fopen("./time.txt", "a+")) == NULL)
PRINT_ERR("fopen error");
line = get_file_line(fp);
ts = ots = 0;
while (1) {
if ((ts = time(NULL)) == -1)
PRINT_ERR("time error");
if (ts != ots) {
ots = ts;
if ((tm = localtime(&ts)) == NULL)
PRINT_ERR("localtime error");
snprintf(tim, sizeof(tim), "%d.%d-%02d-%02d %02d:%02d:%02d\n",
line++, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
fputs(tim, fp);
fflush(fp);
}
}
fclose(fp);
return 0;
}
程序现象:
2. 将十六进制字符串转换为整型数字
下面程序实现:将16进制的字符串转换为10进制的数字。
#include <stdio.h>
int hex_to_int(char hex[]) {
int decimal = 0;
int digit_value;
int i = 0;
// 计算每个十六进制位的值,并将其相加
while (hex[i] != '\0') {
char current_char = hex[i];
if (current_char >= '0' && current_char <= '9') {
digit_value = current_char - '0';
} else if (current_char >= 'a' && current_char <= 'f') {
digit_value = current_char - 'a' + 10;
} else if (current_char >= 'A' && current_char <= 'F') {
digit_value = current_char - 'A' + 10;
} else {
printf("Invalid hexadecimal string.\n");
return 0;
}
decimal = decimal * 16 + digit_value;
i++;
}
return decimal;
}
int main() {
char hex_string[] = "ABCD"; // 十六进制字符串
int decimal = hex_to_int(hex_string); // 将十六进制字符串转换为整型数字
printf("Decimal: %d\n", decimal); // 打印转换后的十进制数
return 0;
}
代码运行现象:
3.给BMP格式的图片打马赛克
下面程序实现对BMP格式的图片打马赛克:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
unsigned char b;
unsigned char g;
unsigned char r;
} RGB_t;
#define MOSIC_WIDTH 10
#define MOSIC_HIGH 10
#define PRINT_ERR(errmsg) \
do { \
perror(errmsg); \
printf("%s:%s:%d\n",__FILE__,__func__,__LINE__);\
return -1; \
} while (0)
int main(int argc, const char* argv[])
{
FILE* fp;
unsigned int size, offset, width, high;
unsigned short pix;
// 1.对命令行参数校验
if (argc != 2) {
fprintf(stderr, "input error,try again\n");
fprintf(stderr, "usage: ./a.out xxx.bmp\n");
return -1;
}
// 2.打开图片
if ((fp = fopen(argv[1], "r+")) == NULL)
PRINT_ERR("fopen error");
// 3.读取图片信息
fseek(fp, 2, SEEK_SET);
fread(&size, 4, 1, fp);
printf("size = %d\n", size);
fseek(fp, 4, SEEK_CUR);
fread(&offset, 4, 1, fp);
printf("offset = %d\n", offset);
fseek(fp, 18, SEEK_SET);
fread(&width, 4, 1, fp);
printf("width = %d\n", width);
fread(&high, 4, 1, fp);
printf("high = %d\n", high);
fseek(fp, 2, SEEK_CUR);
fread(&pix, 2, 1, fp);
printf("pix = %d\n", pix);
// 4.打马赛克
RGB_t(*img)[width] = malloc(width * high * (pix / 8));
// 4.1将图片的数据读出来
fseek(fp, 54, SEEK_SET);
for (int i = 0; i < high; i++) {
for (int j = 0; j < width; j++) {
fread(&img[i][j], sizeof(RGB_t), 1, fp);
}
}
// 4.2打马赛克
for (int i = 0; i < (high / MOSIC_HIGH) * MOSIC_HIGH; i += MOSIC_HIGH) {
for (int j = 0; j < (width / MOSIC_WIDTH) * MOSIC_WIDTH; j += MOSIC_WIDTH) {
for (int x = 0; x < MOSIC_HIGH; x++) {
for (int y = 0; y < MOSIC_WIDTH; y++) {
img[i + x][j + y] = img[i][j];
}
}
}
}
// 4.3将图片的数据写入到文件中
fseek(fp, 54, SEEK_SET);
for (int i = 0; i < high; i++) {
for (int j = 0; j < width; j++) {
fwrite(&img[i][j], sizeof(RGB_t), 1, fp);
}
}
return 0;
}
程序现象:
4.对BMP程序打马赛克进阶
下面程序利用C++ QT程序将上面的功能进行了拓展,可以实现界面选择图片处理,当你理解了上面的程序之后,利用C++结合QT就能快速上手做出一个图像处理的demo程序。
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
#include <QImage>
#include <QLabel>
#include <QFileDialog>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void openImage();
void processImage();
void saveImage();
private:
QLabel *imageLabel; // 用于显示图像的控件
QImage originalImage; // 原始图像
QImage processedImage; // 处理后的图像
};
#endif // MAINWINDOW_H
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
this->setFixedSize(1250,800);
imageLabel = new QLabel(this);
setCentralWidget(imageLabel);
QPushButton *openButton = new QPushButton("打开图片", this);
connect(openButton, &QAbstractButton::clicked, this, &MainWindow::openImage);
QPushButton *processButton = new QPushButton("处理图片", this);
connect(processButton, &QAbstractButton::clicked, this, &MainWindow::processImage);
processButton->move(150,0);
QPushButton *saveButton = new QPushButton("保存图片", this);
connect(saveButton, &QAbstractButton::clicked, this, &MainWindow::saveImage);
saveButton->move(300,0);
}
MainWindow::~MainWindow()
{
}
void MainWindow::openImage()
{
QString imagePath = QFileDialog::getOpenFileName(this, "选择图像", "", "BMP 图像 (*.bmp)");
if (!imagePath.isEmpty())
{
originalImage.load(imagePath);
imageLabel->setPixmap(QPixmap::fromImage(originalImage));
imageLabel->adjustSize();
}
}
void MainWindow::processImage()
{
if (!originalImage.isNull())
{
processedImage = originalImage.copy(); // 复制原始图像进行处理
int gridSize = 16; // 马赛克块的大小
for (int x = 0; x < processedImage.width(); x += gridSize)
{
for (int y = 0; y < processedImage.height(); y += gridSize)
{
QRgb averageColor = processedImage.pixel(x, y);
for (int i = 0; i < gridSize; i++)
{
for (int j = 0; j < gridSize; j++)
{
int newX = qMin(x + i, processedImage.width() - 1);
int newY = qMin(y + j, processedImage.height() - 1);
processedImage.setPixel(newX, newY, averageColor);
}
}
}
}
imageLabel->setPixmap(QPixmap::fromImage(processedImage));
imageLabel->adjustSize();
}
}
void MainWindow::saveImage()
{
if (!processedImage.isNull())
{
QString savePath = QFileDialog::getSaveFileName(this, "保存图像", "", "BMP 图像 (*.bmp)");
if (!savePath.isEmpty())
{
processedImage.save(savePath);
}
}
}
程序现象:
5.在linux中获取本地IP的程序
下面程序是在linux中获取本地IP的程序:
#include <stdio.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#define MAX_IP_COUNT 3
#define IP_ADDR_LEN INET_ADDRSTRLEN
int get_local_ip(char ipList[MAX_IP_COUNT][IP_ADDR_LEN]) {
struct ifaddrs *ifAddrStruct;
char ipAddr[IP_ADDR_LEN];
void *tmpAddrPtr;
int ipCount = 0;
// 获取网络接口列表
if (getifaddrs(&ifAddrStruct) == -1) {
perror("getifaddrs");
return 0;
}
// 遍历网络接口列表
while (ifAddrStruct != NULL) {
if (ifAddrStruct->ifa_addr->sa_family == AF_INET) {
tmpAddrPtr = &((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
inet_ntop(AF_INET, tmpAddrPtr, ipAddr, IP_ADDR_LEN);
// 排除回环地址
if (strcmp(ipAddr, "127.0.0.1") != 0) {
if (ipCount < MAX_IP_COUNT) {
memcpy(ipList[ipCount], ipAddr, IP_ADDR_LEN);
ipCount++;
} else {
break;
}
}
}
ifAddrStruct = ifAddrStruct->ifa_next;
}
freeifaddrs(ifAddrStruct);
return ipCount;
}
int main() {
char ipAddrList[MAX_IP_COUNT][IP_ADDR_LEN];
int addrCount;
memset(ipAddrList, 0, sizeof(ipAddrList));
addrCount = get_local_ip(ipAddrList);
if (addrCount > 0) {
printf("Server Local IP:\n");
for (int i = 0; i < addrCount; i++) {
printf("%d: %s\n", i+1, ipAddrList[i]);
}
} else {
printf("No local IP address found.\n");
}
return 0;
}
程序现象: