第一个hello word 驱动加载失败--------

博主尝试自行加载驱动模块,并在遇到问题时记录了整个操作过程。包括内核版本检查、模块代码与MAKEFILE配置、编译过程、解决内核版本不匹配的方法以及最终加载失败的尝试。

                   今天尝试自己加载第一个驱动模块,根据惯例hello word 然后失败了,现在说明我的操作过程,请个位看看。

首先我的内核版本:


模块代码与MAKEFILE

     

#include<linux/init.h>
#include<linux/module.h>

MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
    printk("hello,world\n");
    return 0;
}

static void hello_exit(void)
{
    printk("GOODBYE,world\n");
}

module_init(hello_init);
module_exit(hello_exit);

obj-m +=Hello.o  
CURRENT_DIR:=$(shell pwd)  
KERNEL_DIR:=$(shell uname -r)  
KERNEL_PATH:=/usr/src/kernels/$(KERNEL_DIR)  
  
all:  
	    make -C $(KERNEL_PATH) M=$(CURRENT_DIR) modules  
clean:  
	    make -C $(KERNEL_PATH) M=$(CURRENT_DIR) clean  

编译通过:

  

      

   这是编译的结果,没有报错。

   首先查看了/usr/src 这里并没有源码树,所以执行  yum install kernel-devel    命令安装源码树

   但是安装完成后是4.0.7 版本内核源码树,但是现在内核版本是4.0.6 于是更新yum update

   但是显示已经更新4.0.7 版本,重新启动后还是4.0.6   

   此处第一次脑洞大开,将/usr/src/ 下最新的4.0.7 源码树名称更改为 4.0.6

   但是modinfo Hello.ko    的vermagic  还是4.0.7

   于是更改/usr/src/kernels/4.0.6-200.fc21.x86_64/include/linux/vermagic.h   文件

   本来是:

       

     更改为:

          

   

       强制给一个和PC 同样的内核版本号

这是重新编译后的结果vermagic 已经改变

然后再次尝试加载:


                        

然后加载再次失败

请各位看看到底是哪里出错?

根据#include “lcd.h” #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> #include <string.h> #include <stdlib.h> //全局变量 int fd_lcd; //帧缓冲设备文件的文件描述符 int fb_size = 8004804; //帧缓冲设备文件的大小 unsigned int *pmap; //映射区首地址 /******************************************** 功能:初始化LCD显示屏 返回值: -1:失败 0:成功 参数:无 ********************************************/ int lcdInit() { //打开帧缓冲设备文件(/dev/fb0) fd_lcd = open(“/dev/fb0”,O_RDWR); if (-1 == fd_lcd) { perror(“open lcd error”); return -1; } //映射 pmap = mmap(NULL, fb_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd_lcd, 0); if (MAP_FAILED == pmap) { //映射失败 perror(“mmap error”); close(fd_lcd); return -1; } return 0; } /******************************************** 功能:关闭LCD显示屏 返回值:无 参数:无 ********************************************/ void lcdClose() { //解除映射,释放内存 munmap(pmap, fb_size); //关闭帧缓冲设备文件 close(fd_lcd); } /******************************************** 功能:显示背景颜色 返回值:无 参数: color:要显示的颜色值 ********************************************/ void lcdBrushBG(unsigned int color) { for (int y = 0; y < 480; y++) { for (int x = 0; x < 800; x++) { (pmap + y800 + x) = color; } } } /******************************************** 功能:在指定的位置像素点 返回值:无 参数: x,y:像素点的坐标 color:像素点显示的颜色值 ********************************************/ void lcdDrawPoint(int x,int y,unsigned int color) { if (x >= 0 && x < 800 && y >= 0 && y < 480) { //是屏幕范围内的点,画像素点 (pmap + y800 + x) = color; } } /******************************************** 功能:在指定的位置画矩形(实心) 返回值:无 参数: x0,y0:矩形显示的位置(左上顶点的坐标) w,h:矩形的宽度和高度 color:矩形的颜色值 ********************************************/ void lcdDrawRect(int x0,int y0,int w,int h,unsigned int color) { for (int y = y0; y < y0+h; y++) { for (int x = x0; x < x0+w; x++) { lcdDrawPoint(x,y,color); } } } /******************************************** 功能:在指定的位置画圆形(实心) 返回值:无 参数: x0,y0:圆心的坐标 r:半径 color:圆的颜色值 ********************************************/ void lcdDrawCircle(int x0,int y0,int r,unsigned int color) { for (int y = y0-r; y < y0+r; y++) { for (int x = x0-r; x < x0+r; x++) { if ((y-y0)(y-y0)+(x-x0)(x-x0) <= r*r) { //这个坐标到圆心的距离小于等于半径(是圆内的点) lcdDrawPoint(x,y,color); } } } } /******************************************** 功能:在指定的位置显示文字 返回值:无 参数: x0,y0:文字显示的位置(左上顶点的坐标) word:文字取模结果的首地址 w,h:文字的宽度和高度(像素点个数) color:文字的颜色值 ********************************************/ void lcdDrawWord(int x0,int y0,unsigned char word,int w,int h,unsigned int color) { //遍历取模结果 int bytes_line = w/8; //每一行数据需要用多少个字节来保存 for (int i = 0; i < w/8h; i++) { //每一个字节的数据对应8个像素点的状态 for (int j = 0; j <= 7; j++) { if(word[i]>>7-j & 0x01) { //是文字上的点,画像素点 int x = j + (i%bytes_line)*8 + x0; int y = i/bytes_line + y0; lcdDrawPoint(x,y,color); } } } } /******************************************** 功能:在指定的位置显示字符串(每个汉字占3个字节) 返回值:无 参数: x0,y0:字符串显示的位置(第一字符左上顶点的坐标) count:要显示的字符个数 word:字符串取模结果的首地址 w,h:字符的宽度和高度(像素点个数) color:字符的颜色值 ********************************************/ void lcdDrawStr(int x0,int y0,int count,unsigned char word,int w,int h,unsigned int color) { //逐个显示字符 for (int i = 0; i < count; i++) { lcdDrawWord(x0+iw,y0,word+iwh/8,w,h,color); } } /******************************************** 功能:在指定的位置显示数字(正整数) 返回值:无 参数: x0,y0:数字显示的位置(左边第一个数字左上顶点的坐标) number:要显示的数字值 word:数字0~9取模结果的首地址 w,h:数字的宽度和高度(像素点个数) color:数字的颜色值 ********************************************/ void lcdDrawNumber(int x0,int y0,int number,unsigned char *word,int w,int h,unsigned int color) { if (number < 0) { return; } //提取数字各位的值 char bits[20] = {0}; //保存数字各位的值 int wei = 0; //记录数字的位数 //如果数字是0,那么就是一个一位数 if (number == 0) { wei = 1; } //循环获取数字个位的数,直到number为0 while (number) { bits[wei++] = number%10; //提取个位数 number /= 10; //去除个位数 } //显示数字 for (int i = wei-1; i >= 0; i–) { lcdDrawWord(x0+(wei-1-i)*w,y0,word+bits[i]wh/8,w,h,color); } } /******************************************** 功能:在指定的位置显示BMP图片 返回值:无 参数: x0,y0:图片显示的位置(左上顶点的坐标) pic_path:要显示的图片文件的路径名 ********************************************/ void lcdDrawBMP(int x0,int y0,char pic_path) { //打开图片文件 int fd_pic = open(pic_path,O_RDONLY); if (-1 == fd_pic) { perror(“open pic error”); return; } //读取图片的参数(魔数、像素数组文件偏移量、宽度、高度、色深) short MS,depth; //魔数、色深 int offset,w,h; //像素数组的文件偏移量、图片宽度、图片高度 read(fd_pic,&MS,2); //判断当前图片是不是BMP图片 if (0x4D42 != MS) { //不是BMP图片 printf(“this pic is not BMP!\n”); close(fd_pic); return; } lseek(fd_pic,0x0A,SEEK_SET); read(fd_pic,&offset,4); lseek(fd_pic,0x12,SEEK_SET); read(fd_pic,&w,4); read(fd_pic,&h,4); lseek(fd_pic,0x1C,SEEK_SET); read(fd_pic,&depth,2); if (depth < 24) { //该BMP图片是24位以下的BMP图片,当前代码不支持显示 printf(“The depth of this image is less than 24 bits and thus cannot be displayed.\n”); close(fd_pic); return; } // printf(“MS=0x%x,offset=0x%x,w=%d,h=%d,deepth=%d\n”,MS,offset,w,h,depth); //读取像素数组数据 int full_bytes_line = (4-(wdepth/8)%4)%4; //每一行填充的字节数 = (4 - 一行像素点颜色值的有效字节数%4)%4 int buf_size = (w*depth/8+full_bytes_line)*abs(h); //像素数组的大小 = 像素点颜色值的有效字节数+填充字节数 unsigned char buf[buf_size]; //用来保存像素数组数据 lseek(fd_pic,offset,SEEK_SET); read(fd_pic,buf,buf_size); //遍历图片上的每个像素点,将其颜色值提取出来按照argb的顺序重新排列组合,并显示到屏幕上去 unsigned char a,r,g,b; //4个颜色分量 unsigned char *p = buf; //为了方便访问数据,通过指针来访问 for (int y = 0; y < abs(h); y++) { for (int x = 0; x < w; x++) { //获取一个像素点的4个颜色分量值 b = *p++; g = *p++; r = *p++; if (depth == 24) { //是一个24位的BMP图片,只有3个颜色分量,a需要手动赋值 a = 0; } else if (depth == 32) { //是一个32位的BMP图片,有4个颜色分量,a可以直接获取 a = *p++; } //将这4个颜色分量按照 a r g b 的顺序重新排列组合成一个32位的颜色值 // a: 1001 1101 // r: 0101 0000 // g: 1010 0010 // b: 0000 1111 // a << 24: // 1010 1101 0000 0000 0000 0000 0000 0000 // r << 16: // 0101 0000 0000 0000 0000 0000 // g << 8: // 1010 0010 0000 0000 // b << 0: // 0000 1111 // a << 24 | r << 16 | g << 8 | b: // 1010 1101 0101 0000 1010 0010 0000 1111 unsigned int color = a << 24 | r << 16 | g << 8 | b; //将该像素点颜色值显示到屏幕上去 if (h > 0) { //图像在保存的时候是从下往上保存的,显示也要从下往上显示 lcdDrawPoint(x+x0,h-1-y+y0,color); } else { lcdDrawPoint(x+x0,y+y0,color); } } //每显示完一行像素点的颜色值,就需要跳过后面的填充数据 p += full_bytes_line; } //关闭图片文件 close(fd_pic); } 写一个c语言文字滚屏的主程序
最新发布
07-12
要在你提供的 LCD 驱动基础上实现**文字横向滚屏效果(Scrolling Text)**,我们需要利用 `lcdDrawStr` 函数来逐帧绘制字符串,并通过控制字符串的 x 坐标不断变化,从而实现从右向左的滚动动画。 --- ## ✅ 实现思路 1. **定义一个字符串**:如 `"Hello, Embedded System!"`。 2. **计算总宽度**:根据字体大小(假设是 8x16 字体),每个字符占 8 像素宽。 3. **主循环中更新 x 坐标**:使字符串从屏幕右侧逐步移动到左侧。 4. **每帧前清空上一帧的文字区域**:避免残影。 5. **使用 `usleep()` 控制帧率**。 6. **当文字完全移出屏幕后,重新从右侧开始**。 --- ## ✅ 主程序代码:实现横向文字滚屏 ```c #include "lcd.h" #include <unistd.h> #include <stdio.h> #include <string.h> // 假设字体为 8x16 的 ASCII 字符点阵 #define FONT_WIDTH 8 #define FONT_HEIGHT 16 // 外部字模数组(请确保你在其他文件或头文件中定义了这个) extern unsigned char font_ascii[][16]; int main() { // 初始化LCD if (lcdInit() != 0) { printf("Failed to initialize LCD.\n"); return -1; } // 清屏为黑色 lcdBrushBG(COLOR_BLACK); // 要滚动的字符串 const char *text = "Welcome to Embedded System Scrolling Text Demo!"; int text_len = strlen(text); int total_width = text_len * FONT_WIDTH; // 初始坐标(从屏幕右边开始) int x_start = 800; // 初始在屏幕右边外 int y_start = 480 / 2 - FONT_HEIGHT / 2; // 居中显示在垂直方向 // 滚动参数 int step = 2; // 每次移动像素数 int delay_ms = 30; // 帧延迟时间(毫秒) while (1) { for (int offset = 0; offset <= total_width + 800; offset += step) { int current_x = x_start - offset; int current_y = y_start; // 清除上一帧(只清除文字区域) lcdDrawRect(current_x - step, current_y, total_width, FONT_HEIGHT, COLOR_BLACK); // 显示当前帧的文字 lcdDrawStr(current_x, current_y, text_len, (unsigned char *)font_ascii, FONT_WIDTH, FONT_HEIGHT, COLOR_WHITE); // 延迟 usleep(delay_ms * 1000); } } // 关闭LCD资源(不会执行到这里) lcdClose(); return 0; } ``` --- ## ✅ 关键函数说明 | 函数 | 作用 | |------|------| | `lcdInit()` | 初始化帧缓冲设备 | | `lcdBrushBG(COLOR_BLACK)` | 清屏为黑色背景 | | `lcdDrawStr(...)` | 在指定位置绘制字符串 | | `lcdDrawRect(...)` | 绘制矩形用于清除上一帧内容 | | `usleep(...)` | 控制帧率,实现动画流畅度 | --- ## ✅ 注意事项 - **字模数组** `font_ascii` 必须提前定义并包含进项目中。 - 如果你希望支持中文,需要加载中文字库并修改 `lcdDrawStr` 支持 Unicode 或 GBK 编码。 - 若滚动过程中出现残影,建议: - 使用双缓冲技术。 - 或者每次全屏刷新后再重绘文字。 --- ## ✅ 扩展功能建议 | 功能 | 实现方法 | |------|----------| | 上下滚动 | 修改 `y_start` 和 `offset` | | 双缓冲 | 使用两个帧缓冲区交替绘制 | | 加速/减速控制 | 动态改变 `step` 步长或 `delay_ms` 时间 | | 多行滚动 | 创建多个滚动区域,每行独立滚动 | --- ##
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值