找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2774|回复: 18
收起左侧

keilC51单片机怎么实现字节对齐?

  [复制链接]
回帖奖励 15 黑币 回复本帖可获得 15 黑币奖励! 每人限 1 次
ID:834913 发表于 2021-12-29 17:11 | 显示全部楼层 |阅读模式
现在正常做一个任务是将一个BMP显示程序从STM32移植到一个51内核的单片机上,下面是解析BMP的结构体 可以看到都用__packed关键字进行了一字节对齐
//BMP信息头
typedef __packed struct
{
    DWORD biSize ;                   //说明BITMAPINFOHEADER结构所需要的字数。
    LONG  biWidth ;                   //说明图象的宽度,以象素为单位
    LONG  biHeight ;           //说明图象的高度,以象素为单位
    WORD  biPlanes ;           //为目标设备说明位面数,其值将总是被设为1
    WORD  biBitCount ;           //说明比特数/象素,其值为1、4、8、16、24、或32
    DWORD biCompression ;  //说明图象数据压缩的类型。其值可以是下述值之一:
        //BI_RGB:没有压缩;
        //BI_RLE8:每个象素8比特的RLE压缩编码,压缩格式由2字节组成(重复象素计数和颜色索引);  
    //BI_RLE4:每个象素4比特的RLE压缩编码,压缩格式由2字节组成
          //BI_BITFIELDS:每个象素的比特由指定的掩码决定。
    DWORD biSizeImage ;//说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0  
    LONG  biXPelsPerMeter ;//说明水平分辨率,用象素/米表示
    LONG  biYPelsPerMeter ;//说明垂直分辨率,用象素/米表示
    DWORD biClrUsed ;           //说明位图实际使用的彩色表中的颜色索引数
    DWORD biClrImportant ; //说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。
}BITMAPINFOHEADER ;

//BMP头文件
typedef __packed struct
{
    WORD  bfType ;     //文件标志.只对'BM',用来识别BMP位图类型
    DWORD bfSize ;           //文件大小,占四个字节
    WORD  bfReserved1 ;//保留
    WORD  bfReserved2 ;//保留
    DWORD bfOffBits ;  //从文件开始到位图数据(bitmap data)开始之间的的偏移量
}BITMAPFILEHEADER;

//彩色表
typedef __packed struct
{
        BYTE    rgbBlue;                 /*指定蓝色强度 */
        BYTE    rgbGreen;                                 /*指定绿色强度 */
        BYTE    rgbRed;                                         /*指定红色强度 */
        BYTE    rgbReserved;                         /*保留,设置为0*/
} RGBQUAD;

//位图信息头
typedef __packed struct
{
        BITMAPFILEHEADER bmfHeader;
        BITMAPINFOHEADER bmiHeader;  
        RGBQUAD bmiColors[1];  
}BITMAPINFO;



但是keil51似乎不能这么做 我试过了其他方法 比如说伪指令#pragma pack(n) 也行不通 编译器不能识别 这样解析函数就无法正确解析BMP图片了 所以想请教一下有了解BMP图片或者字节对齐的大神我该怎么办


下面是BMP解析函数
/*********************************************************************
* 名    称:BmpDecode()
* 功    能:解码BMP图片
* 入口参数:address        地址        
* 出口参数:0x00           不是BMP位图
*                 0x01           位图大小不对
            0x02           读取正确   
**********************************************************************/

u8 BmpDecode(u32 address)
{
    u8          readcount =0;         
        u8          rgb = 0;
        u8          color_byte =0;                                        /*颜色位数          */                                                
        u16         count = 0;                                                /*数据偏移值        */
        u16         uiTemp = 0;                            /*x轴方向像素总和   */
        u16         xpels = 0;                                                 /*x轴方向像素计数器 */
        u16         ypels = 0;                                                 /*y轴方向像素计数器 */
        u16         pageadd = 0;                    /*页地址            */
        u32         countpix = 0;                                        /*x轴方向像素累加器 */

        BITMAPINFO *pbmp;                                                /*bmp文件头指针     */
        DWORD       tmp_color,color;                        /*颜色值            */


               
   Read_BmpData(address);                            /* 读取1024字节到jpg_buffer */
        
        
        pbmp = (BITMAPINFO*)jpg_buffer;                   /* 得到BMP的头部信息        */
        if (pbmp->bmfHeader.bfType != 0x424d)                      /*如果不是BMP图片           */
        {
            return 0x00;
        }
        else
        {
            count      = pbmp->bmfHeader.bfOffBits ;              /*数据偏移,得到数据段的开始地址*/
            color_byte = pbmp->bmiHeader.biBitCount/8;        /*彩色位 16/24/32              */

                PICINFO.ImgHeight = pbmp->bmiHeader.biHeight; /*得到图片高度                                  */
            PICINFO.ImgWidth  = pbmp->bmiHeader.biWidth;  /*得到图片宽度                                 */
               
                if(        PICINFO.ImgWidth != 140 || PICINFO.ImgHeight != 32)
                {
                    return 0x01;
                }
        

            if((PICINFO.ImgWidth*color_byte)%4)
                {
                    uiTemp = ((PICINFO.ImgWidth*color_byte)/4+1)*4;
                }
             else
                {
                    uiTemp = PICINFO.ImgWidth*color_byte;
                }



                rgb   = 0;
                xpels = 0;
                ypels = 0;
                pageadd = 0;
                readcount = 0;
                color = 0x00;
                memset(BMP_buffer,0,sizeof(BMP_buffer));
        
                while(1)
                {
                    while( count < 1024 )
                        {
                            if(color_byte == 3)                                  /*24位颜色图                */
                                {
                                           switch (rgb)
                                        {
                                                case 0:
                                                        tmp_color = jpg_buffer[count]*0.299 ;
                                                        color += tmp_color;
                                                        break ;           
                                                case 1:
                                                        tmp_color = jpg_buffer[count]*0.587 ;                        
                                                        color += tmp_color ;
                                                        break;         
                                                case 2 :
                                                        tmp_color = jpg_buffer[count]*0.114 ;
                                                        color += tmp_color ;
                                                        break ;                        
                                        }
                                }
                                rgb++;
                                count++ ;

                                if(rgb == color_byte)                /*水平方向读取到1像素数数据后放入缓冲区中*/
                                {
                                   xpels++;                          /*x轴增加一个像素                                */
                                   if(xpels <= PICINFO.ImgWidth)         /*如果未扫描完一行                                */
                                   {
                                         if(color > 255)  
                                     {
                             color = 0;  
                                     }
                         if(color < 0 )
                                                   {
                                           color = 255;   
                                               }
                                         if(color > 127)
                                             {
                                                 BMP_buffer[xpels-1] = BMP_buffer[xpels-1]| 1<<(ypels%8);
                                             }
                                   }
                                   color = 0x00;
                                   rgb   = 0;
                                }

                                countpix++;                                                   /*像素累加                             */

                                if(countpix >= uiTemp)                                        /*水平方向像素值到了.换行                 */
                                {
                                   ypels++;
                                   if(ypels%8 == 0)                                                              /*如果解码一页                                 */
                                   {
                                       LCD_PutBmp(pageadd,BMP_buffer);                        /*显示到lcd                                     */
                                           memset(BMP_buffer,0,sizeof(BMP_buffer));
                                           pageadd++;
                                   }

                                   if(ypels >= PICINFO.ImgHeight)   
                                   {
                                       return 0x02 ;                                                   /*正常退出                                   */
                                   }

                                   xpels   = 0;
                                   countpix= 0;
                                   color   = 0x00;
                                   rgb     = 0;
                                }
                                
                        }
                        readcount++;
                        
                        Read_BmpData(address + readcount*1024);
                        count = 0 ;
                }
        }
}

回复

使用道具 举报

ID:883242 发表于 2021-12-29 17:44 | 显示全部楼层
这么大的工作量是51这么ws的东西承担不起的,先别考虑什么对齐问题,先把编译搞通过了证明在51上面跑起来再想细节问题。
回复

使用道具 举报

ID:313048 发表于 2021-12-29 17:48 | 显示全部楼层
51单片机能解析BMP图片?
我记得是不能的吧,显示图片是没问题的,直接从存储器中读取,可以是外挂FLASH啥的,串口接收的数据也可以,SD卡和USB好像不行,而且是需要你转化为hex格式才行。
回复

使用道具 举报

ID:313048 发表于 2021-12-29 17:49 | 显示全部楼层
51单片机是8位机,所有不需要字节对齐,本身就是单字节对齐的。你这还去字节对齐就过于画蛇添足了。
回复

使用道具 举报

ID:834913 发表于 2021-12-29 18:06 | 显示全部楼层
AUG 发表于 2021-12-29 17:48
51单片机能解析BMP图片?
我记得是不能的吧,显示图片是没问题的,直接从存储器中读取,可以是外挂FLASH啥 ...

用的是迪文的T5L 51内核的 计划是将图片数据读取到flash 再从flash读出来解析显示 那就不是字节对齐的问题了 我再想想吧 谢谢回答
回复

使用道具 举报

ID:834913 发表于 2021-12-29 18:09 | 显示全部楼层
Hephaestus 发表于 2021-12-29 17:44
这么大的工作量是51这么猥琐的东西承担不起的,先别考虑什么对齐问题,先把编译搞通过了证明在51上面跑起来 ...

谢谢回复 那我再想想
回复

使用道具 举报

ID:893997 发表于 2021-12-29 23:07 | 显示全部楼层
这程序跑不动啊,用增强型51都未必可以,运算量太大了
回复

使用道具 举报

ID:888298 发表于 2022-4-8 09:55 | 显示全部楼层
不万能的喜剧 发表于 2021-12-29 18:06
用的是迪文的T5L 51内核的 计划是将图片数据读取到flash 再从flash读出来解析显示 那就不是字节对齐的问 ...

这个平台BMP最好是做成ICL,如果是实时显示,最好用jpeg,你这种写入flash的方法会损耗FLASH
回复

使用道具 举报

ID:982617 发表于 2022-4-13 17:42 | 显示全部楼层
程序可能太复杂了 试试精简吧
回复

使用道具 举报

ID:1004160 发表于 2023-12-20 15:10 | 显示全部楼层
同样遇到字节对齐的问题,估且算是吧。 问题就是:
回复

使用道具 举报

ID:1004160 发表于 2023-12-20 15:16 | 显示全部楼层
同样遇到字节对齐的问题,问题就是:
汉字取模后,只有一个汉字无法显示,这个汉字是“过”这个字。存在结构体中用汉字来当索引,检索取模后的十六进制数。结构体如下:
typedef struct  
{
        unsigned char Index[2];
        unsigned char Msk[128];
}typFNT_GB32;
//#pragma pack()

const typFNT_GB32 code tfont32[]={
"未",0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x03,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x81,0x01,0xC0,0xFF,
0xFF,0x03,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x0C,0xF8,0xFF,0xFF,0x1F,0x00,0xE0,0x03,0x00,
0x00,0xE0,0x05,0x00,0x00,0xB0,0x0D,0x00,0x00,0xB8,0x09,0x00,0x00,0x98,0x11,0x00,0x00,0x8C,0x31,0x00,0x00,0x86,0x61,0x00,0x00,0x83,0xC1,0x01,0x80,0x81,0x81,0x03,0x60,0x80,
0x01,0x0F,0x30,0x80,0x01,0x3E,0x08,0x80,0x01,0x0C,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,/*"未",0*/


通过分析发现,当结构内存储的是“过”这个字的时候是无法显示的。调试发现,Index[2]数组中的Index[1]取值不完整。如下:
k=10
indx0=0xd5
indx1=0xcf
k=11
indx0=0xb9
indx1=0x0
k=12
indx0=0xc7
indx1=0xb7

上边的“k=11”这个就是“过”这个汉字的序号,打印出来后居然是“indx1=0x0”,缺少数据,正常应该是“indx1=0xfd”。即:indx0=0xb9,indx1=0xfd。正好对应GB2312码表中“过”这个汉字十六进制编码0xb9fd。

请各位大神指教,如何解决。问题是:只有这一个汉字这样,其它汉字没有问题。从上述打印出来的k=10、k=12的索引汉字就能看出来。
回复

使用道具 举报

ID:526108 发表于 2023-12-20 15:25 | 显示全部楼层
51没有字节对齐概念,默认就是紧凑型的
回复

使用道具 举报

ID:883242 发表于 2023-12-20 16:19 | 显示全部楼层
xinwuhen 发表于 2023-12-20 15:16
同样遇到字节对齐的问题,问题就是:
汉字取模后,只有一个汉字无法显示,这个汉字是“过”这个字。存在结 ...

8位机哪来的对齐问题?
回复

使用道具 举报

ID:1101997 发表于 2023-12-21 09:07 | 显示全部楼层
风之痕于梦想 发表于 2021-12-29 23:07
这程序跑不动啊,用增强型51都未必可以,运算量太大了

32位肯定效率要高一些,不过迪文的OS核跑起来还是很快的,主频好像是快300Mhz,指令周期基本都是1.
回复

使用道具 举报

ID:458247 发表于 2023-12-21 09:31 | 显示全部楼层
xinwuhen 发表于 2023-12-20 15:16
同样遇到字节对齐的问题,问题就是:
汉字取模后,只有一个汉字无法显示,这个汉字是“过”这个字。存在结 ...

你这个是keil c51的0xFDbug,你只要把index写成"过\0xFD"就好了
回复

使用道具 举报

ID:1034262 发表于 2023-12-21 10:48 | 显示全部楼层
8位机没有对齐问题,永远都是对齐的。
回复

使用道具 举报

ID:1004160 发表于 2023-12-26 23:19 | 显示全部楼层
yzw846562238 发表于 2023-12-21 09:31
你这个是keil c51的0xFDbug,你只要把index写成"过\0xFD"就好了

感谢,是这个问题。我采用了2种方案。一个是\xFD加在GBK码低8位包含FD的汉字上。 另一种是,我直接修改了Keil51的C51.exe程序。 目前 采用了第2 种方案。一劳永逸。
回复

使用道具 举报

ID:1004160 发表于 2023-12-26 23:20 | 显示全部楼层
一并感谢各位大佬,后来查到问题的解决办法了。\xFD加在无法显示的汉字背后,以及修改Keil下的C51执行文件,自己改了后作为补丁打到了Keil程序里。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表