搜索
bottom↓
回复: 61

结构体、共用体、位段和动态链链表在AVR上的应用

[复制链接]

出0入0汤圆

发表于 2009-8-28 09:22:07 | 显示全部楼层 |阅读模式
呵呵,今天终于在AVRstudio上将动态链表应用进去了,将源代码传上来和大家分享一下编程的乐趣!

阿莫论坛20周年了!感谢大家的支持与爱护!!

如果想吃一顿饺子,就得从冰箱里取出肉,剁馅儿,倒面粉、揉面、醒面,擀成皮儿,下锅……
一整个繁琐流程,就是为了出锅时那一嘴滚烫流油的热饺子。

如果这个过程,禁不住饿,零食下肚了,饺子出锅时也就不香了……《非诚勿扰3》

出0入0汤圆

 楼主| 发表于 2009-8-28 09:31:42 | 显示全部楼层
附件代码
结构体、共用体、位段和动态链链表在AVR上的应用ourdev_475418.rar(文件大小:19K) (原文件名:MP3BoardTest.rar)

出0入0汤圆

 楼主| 发表于 2009-8-30 23:11:25 | 显示全部楼层
动态链表头文件源码:
//双向动态链表应用头文件==============================================================
//作者:LZL
//E-mail:lzllong@126.com   
//2009-8-27
//可动态的完成双向链表的创建、节点添加和删除
//=======================================================================
#ifndef _QUEUEOPERATION_H_
#define _QUEUEOPERATION_H_

//#include <malloc.h>

#define  NULL  0
#define  LEN        sizeof(ReportStruct)
//自定义结构体,可根据具体需求修改
typedef struct   _ReportStruct
{
        int     ReportNum;
        char    ReportCode[21];
        struct  ReportStruct* next;
        struct  ReportStruct* last;
}ReportStruct,*pReportStruct;

struct ReportStruct* creat(void)      //创建链表,返回链表头,只有一个链表项
{
        struct ReportStruct * head;
        head=(ReportStruct *)malloc(LEN); //开辟新单元
        memset(head,0,sizeof(ReportStruct));
        return head;
}

int insert(ReportStruct* head ,ReportStruct* newmember)     //在链表的末尾插入新的链表项
{
        ReportStruct* p1;
        p1=head;
        if(p1->next==NULL)  //只有一项
        {
                p1->next = newmember;
                newmember->last = head;
                newmember->ReportNum = head->ReportNum+1;
                newmember->next = NULL;
                return 1;
        }
        else                                //两项或以上
        {
                p1=p1->next;               
                while(p1->next!=NULL)p1=p1->next;
                p1->next=newmember;
                newmember->last = p1;
                newmember->next = NULL;
                newmember->ReportNum = p1->ReportNum+1;
                return 1;
        }       
        return 0;
}

int del(ReportStruct* head ,unsigned int Index)     //删除第Index项
{
        ReportStruct* p0;
        ReportStruct* p1;
        ReportStruct* p2;
        p1 = head;
        if(p1->ReportNum==Index){free(head);return 1;}//只有一项
        while(p1->next!=NULL)//两项或以上
        {
                p1 = p1->next;
                if(p1->ReportNum == Index)
                {
                        p0 = p1;
                        p1 = p1->last;
                        p1->next = p0->next;
                        free(p0);
                        goto DEAL;
                }
        }
        return 0;
DEAL:
        while(p1->next!=NULL)
        {
                p1=p1->next;
                p1->ReportNum-=1;
        }
        return 1;
}
#endif

出0入0汤圆

发表于 2009-8-31 09:07:56 | 显示全部楼层
能详细讲讲吗?学习学习~~~

出0入0汤圆

 楼主| 发表于 2009-8-31 09:38:13 | 显示全部楼层
呵呵,谭浩强老师的C语言程序设计(第二版)273p-286p讲述的很清楚的哦!

出0入0汤圆

 楼主| 发表于 2009-8-31 09:50:16 | 显示全部楼层
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/delay.h>
#include "QueueOperation.h"
void delayms(int time)  //随意的延时函数
{
        while(time--)
        {
                _delay_ms(200);
                wdt_reset();
                _delay_ms(200);
                wdt_reset();
        }
}

union  Pack_dat //共用体
{
        struct Pack_LedIO        //位段结构体
        {
                unsigned char LED0:1;
                unsigned char LED1:1;
                unsigned char LED2:1;
                unsigned char LED3:1;
                unsigned char LED4:1;
                unsigned char LED5:1;
                unsigned char LED6:1;
                unsigned char LED7:1;
        }LedIO;
        unsigned char LEDIO;
}PackDat;

int main(void)
{
        int time = 3;
        DDRC = 0xff;
        PORTC= 0x00;
        PackDat.LEDIO = 0;
        wdt_reset();
        ReportStruct* p1;
        ReportStruct* pErrorReportHead = creat();//创建动态链表
        ReportStruct  newmember;                 //构造新的成员
        newmember.ReportCode[2]=0x55;
        insert(pErrorReportHead ,&newmember);    //将新成员插入链表末尾
        ReportStruct  lasrmember;
        lasrmember.ReportCode[0]=0xaa;       
        if(insert(pErrorReportHead ,&lasrmember))//插入第二个成员
        {
                while(time--)                   //循环3次
                {
                        wdt_reset();         
                        PackDat.LedIO.LED3 = 1;
                        PORTC = PackDat.LEDIO;  //改变PC3输出高电平
                        delayms(5);
                        PackDat.LEDIO = 0;      //PC口全部置低
                        PackDat.LedIO.LED7 = 1;
                        PORTC = PackDat.LEDIO;  //改变PC7输出高电平

                        wdt_reset();
                        delayms(5);
                        PackDat.LEDIO = 0;                       
                        p1=pErrorReportHead->next;
                        PORTC = p1->ReportCode[2];//验证链表的第一个节点是否为newmember,head为第0个节点
                        wdt_reset();
                        delayms(5);                       
                        p1=p1->next;
                        PORTC = p1->ReportCode[0];    //验证链表的第二个节点是否为lasrmember,head为第0个节点

                        wdt_reset();
                        delayms(5);                       
                }
                wdt_reset();
                p1->ReportCode[0] = 0x11;          //改变        lasrmember.ReportCode[0]为0x11
                del(pErrorReportHead ,1);    //删除第一个节点
                p1=pErrorReportHead->next;   //然后再指向第一个节点
                PORTC = p1->ReportCode[0];   //验证第一个节点变为了lasrmember
                while(1)                     //等待
                {
                        wdt_reset();
                        delayms(5);                       
                }
        }
        return 1;
}

出0入0汤圆

发表于 2009-8-31 14:33:57 | 显示全部楼层
很有启发.

出0入0汤圆

发表于 2009-8-31 14:47:55 | 显示全部楼层
保存。等能看懂时研究。

出0入0汤圆

 楼主| 发表于 2009-9-8 22:20:33 | 显示全部楼层
insert函数进行完善,可在链表任意位置插入新节点:

int insert(ReportStruct* head ,ReportStruct* newmember,int Index)     //在链表的任意位置插入新的链表项
{                                                                                                                     //该项不存在,插入到末尾
ReportStruct* p1,p0;
p1=head;
while(p1->next!=NULL&&p1->ReportNum!=Index)p1=p1->next;
if(p1->next==NULL)                    //链表没有这么多项,新节点插入到链尾
{
p1->next=newmember;
newmember->last = p1;
newmember->next = NULL;
newmember->ReportNum = p1->ReportNum+1;
return 1;
}
if(p1->ReportNum==Index)             //当前是第Index项,插入该节点
{
p0=p1->next;
p1->next=newmember;
newmember->last = p1;
newmember->next = p0;
p0->last = newmember;
newmember->ReportNum = p0->ReportNum;
while(p0->next!=NULL)
{
        p0->ReportNum = p0->ReportNum+1;
}
return 1;
}
return 0;
}

出0入0汤圆

发表于 2009-9-18 18:38:00 | 显示全部楼层
等能看懂时研究,谢谢

出0入0汤圆

发表于 2009-9-18 18:58:03 | 显示全部楼层
学以致用,楼主不错。这2个星期也在学习链表!可以参考下,谢谢!

出675入8汤圆

发表于 2009-9-19 10:53:02 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-9-19 23:51:21 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-2-21 10:07:13 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-3-2 16:37:09 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-9 23:35:27 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-12-11 00:34:57 | 显示全部楼层
mm

出0入0汤圆

发表于 2010-12-11 01:11:08 | 显示全部楼层
mark先~~

出0入0汤圆

发表于 2010-12-11 02:06:11 | 显示全部楼层
MARK,慢慢看

出0入0汤圆

发表于 2010-12-11 07:49:34 | 显示全部楼层
我想请问一下,为什么在在类型定义的时候要加*pReportStruct,类型定义后不是直接就可以用ReportStruct定义了么?要指针干嘛?我看到很多程序都是这么写的,一直不明白。
typedef struct   _ReportStruct
{
int     ReportNum;
char    ReportCode[21];
struct  ReportStruct* next;
struct  ReportStruct* last;
}ReportStruct,*pReportStruct;

出0入0汤圆

 楼主| 发表于 2010-12-14 13:04:58 | 显示全部楼层
呵呵,不就是满足不同习惯的人的应用吗?如下:
ReportStruct* p0;
ReportStruct* p1;
ReportStruct* p2;



pReportStruct p0;
pReportStruct p1;
pReportStruct p2;

是相同的意思,适应于不同的编程习惯的人应用!

出10入12汤圆

发表于 2010-12-14 13:30:41 | 显示全部楼层
标记

出0入0汤圆

发表于 2010-12-14 13:33:06 | 显示全部楼层
标  记

出0入0汤圆

发表于 2010-12-15 22:12:36 | 显示全部楼层
回复【21楼】lzllong
-----------------------------------------------------------------------

谢谢你!要的就是你的这句话啊。pReportStruct p0和ReportStruct* p0是一个意思。

出0入0汤圆

发表于 2010-12-16 09:15:47 | 显示全部楼层
回复【21楼】lzllong
呵呵,不就是满足不同习惯的人的应用吗?如下:
reportstruct* p0;  
reportstruct* p1;  
reportstruct* p2;

preportstruct p0;  
preportstruct p1;  
preportstruct p2;
是相同的意思,适应于不同的编程习惯的人应用!
-----------------------------------------------------------------------

都是大学本科,计算机科学系的专业必修课程《数据结构》方面的知识。

      向量 、 堆栈 、 队列 、 十字链表 、 广义表 、二叉树

出0入0汤圆

发表于 2010-12-17 21:15:31 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-18 00:54:16 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-18 08:51:05 | 显示全部楼层
mark

出0入96汤圆

发表于 2010-12-18 09:02:01 | 显示全部楼层
记录

出0入0汤圆

发表于 2010-12-18 09:58:15 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-19 14:47:19 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-3-17 07:21:37 | 显示全部楼层
你说说一般用在什么情况下好了,不知道是用来干嘛的,怎么用再自己查查书就行。。
学习了!
结构体、共用体、位段和动态链链表在AVR上的应用(在什么情况下用什么比较好)

出0入0汤圆

 楼主| 发表于 2011-3-30 20:42:27 | 显示全部楼层
共用体、结构体应用举例:
首先定义如下结构体
union
{
        unsigned char  strTime[7];
        struct Time
        {
                unsigned char Sec;
                unsigned char Minu;
                unsigned char Hour;
                unsigned char Day;
                unsigned char Date;
                unsigned char Month;
                unsigned char Year;
        } NYRTime;
} SystemTime;

填充上面这个共用体的函数为:
void GettimeAndTemperature(void)
{
unsigned int i;
unsigned char h[7] = {0};
for(i=0;i<7;i++)
{
        I2c_Rd_Data(0x00+i,&h,1);
        SystemTime.strTime = 10*(((h&0xf0)>>4)&0x07) + (h&0x0f);
}
for(i=0;i<2;i++)
{
        I2c_Rd_Data(0x11+i,&strTemperature,1);
}
}
显示函数如下:
void ShowAlamTime(void)
{
                GettimeAndTemperature();
                ShowDtypeWORD(0,16,2000+SystemTime.NYRTime.Year);     //年
                ShowDtypeBYTE(8,16,SystemTime.NYRTime.Month);              //月       
                ShowDtypeBYTE(14,16,SystemTime.NYRTime.Date);         //日
                ShowDtypeBYTE(2,32,SystemTime.NYRTime.Hour);          //时
                ShowDtypeBYTE(8,32,SystemTime.NYRTime.Minu);                    //分
                ShowDtypeBYTE(14,32,SystemTime.NYRTime.Sec);          //秒                       
}

上面的三段代码是用在DS3231时钟芯片上的,一般的时钟芯片中的几个常用的时间寄存器地址是连续的,所以在GettimeAndTemperature中可以连续的读出各个时间,然后可以采取ShowAlamTime方式进行显示,使程序看起来更加通俗易懂!

出0入0汤圆

发表于 2011-6-6 01:41:51 | 显示全部楼层
mark
正在折腾结构体位段在共用体里的应用,弄了半天,ICC就是编译不过去,郁闷。
有高手能看下吗?
union hc595_data
{
    uchar data;
    struct BYTES
    {
            unsigned bit0 :1;       
            unsigned bit1 :1;
            unsigned bit2 :1;
            unsigned bit3 :1;
            unsigned bit4 :1;
            unsigned bit5 :1;
            unsigned bit6 :1;
            unsigned bit7 :1;
    }hc595_byte;
};

union hc595_data hc595_data1;
union hc595_data hc595_data2;

以上是定义,下面一条赋值语句,编译报错。
hc595_data1.hc595_byte.bit0=0;

提示为类型不匹配,不知道什么原因。

出0入0汤圆

发表于 2011-6-6 06:51:05 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-6 11:39:07 | 显示全部楼层
回复【21楼】lzllong  
-----------------------------------------------------------------------
看来我的c还是没有学透彻啊

出0入0汤圆

发表于 2011-6-7 09:32:53 | 显示全部楼层
p1->next = newmember;
newmember->last = head;
newmember->ReportNum = head->ReportNum+1;
newmember->next = NULL;


编译到上述语句出现错误,编译器为RVMDK 4.2.
Init.c(59): error:  #513: a value of type "ReportStruct *" cannot be assigned to an entity of type "struct ReportStruct *"








链表结构定义应该是这样的吧,否则出现上述错误!
typedef struct   _ReportStruct
{
        int     ReportNum;
        char    ReportCode[21];
        struct  _ReportStruct *next;
        struct  _ReportStruct *last;
}ReportStruct,*pReportStruct;

出0入0汤圆

 楼主| 发表于 2011-6-16 22:01:59 | 显示全部楼层
回复【34楼】xjmlfm1
-----------------------------------------------------------------------

不知道,你的编译提示什么错误,uchar data; 肯定为unsigned char类型,但是unsigned bit0 :1中只写unsigned的话C语言中应该默认为unsigned int类型,所以类型应该不匹配。

出0入0汤圆

 楼主| 发表于 2011-6-16 22:03:54 | 显示全部楼层
回复【37楼】Adrian
-----------------------------------------------------------------------

不知道你改完后编译过去没有?我的在AVRStdio中编译是没有问题的。

出0入0汤圆

发表于 2011-8-5 15:38:50 | 显示全部楼层
回复【39楼】lzllong  
-----------------------------------------------------------------------
感谢LZ,当初考三级数据库技术的时候老是理解不了这些东东,又看了遍感觉现在明晰多了。
我在RVMDK4.20下编译的确有问题,改成这样没问题;IAR For ARM 6.20下也没问题。看来还是与编译器脾气有关系,不过感觉改成struct  _ReportStruc更合理些,按照顺序理解,ReportStruc在这个结构体定义完成后才有效,而_ReportStruc在定义之前,相当于结构体标签,定义指针的时候编译器就可以识别了。所以感觉struct  ReportStruc定义指针只是有些编译器可以编译通过的。不知理解是否恰当。
typedef struct   _ReportStruct  
{  
int     ReportNum;  
char    ReportCode[21];  
struct  _ReportStruct *next;  
struct  _ReportStruct *last;  
}ReportStruct,*pReportStruct;


还有,LZ补充的在任意位置插入新的节点函数似乎有个小问题,就是在插入新节点后对后续节点的index进行加1,P0并没有重新赋值,指向下一个节点。

while(p0->next!=NULL)
{
p0->ReportNum = p0->ReportNum+1;
}

应该是这样的吧?
while(p0->next!=NULL)
{
p0->ReportNum = p0->ReportNum+1;
p0=P0->next;
}

出0入0汤圆

发表于 2011-8-5 15:48:47 | 显示全部楼层
不错。

出0入0汤圆

发表于 2011-8-6 22:40:06 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-8-7 00:28:19 | 显示全部楼层
保存

出0入0汤圆

发表于 2011-8-7 02:27:59 | 显示全部楼层
有研究,真的研究透动态连表就蛮牛B了,至少是C入门了,哈哈

出0入0汤圆

 楼主| 发表于 2011-8-9 21:48:34 | 显示全部楼层
回复【39楼】lzllong
-----------------------------------------------------------------------

谢谢 Adrian的完善,其实这些代码是用来验证谭浩强老师 C语言程序设计第二版 中关于动态链表的内容的,这段动态链表实际的应用价值并不大,因为大家都知道实现操作系统中的某些机制的双向链表远远要比这个复杂。相反,结构体和共用体的例子反而更使用一些。上面的例子仅供大家参考,很乐意和大家分享编程的乐趣。

出0入0汤圆

发表于 2011-8-9 22:02:22 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-8-9 22:25:49 | 显示全部楼层
学习

出0入0汤圆

发表于 2012-3-7 17:53:04 | 显示全部楼层
mark  正好要用!

出0入0汤圆

发表于 2012-3-7 19:07:07 | 显示全部楼层
mark。

出0入0汤圆

发表于 2012-11-26 15:29:46 | 显示全部楼层
顶一下,正在研究!

出0入0汤圆

发表于 2012-11-26 16:22:47 | 显示全部楼层
Mark 结构体、共用体、位段和动态链链表在AVR上的应用

出0入0汤圆

发表于 2012-11-26 17:42:40 | 显示全部楼层
学习!

出0入0汤圆

发表于 2012-11-26 17:54:35 | 显示全部楼层
好东西,一定要学习一下

出0入0汤圆

发表于 2012-11-27 22:16:35 | 显示全部楼层
mark以后用的上

出0入0汤圆

发表于 2013-4-9 13:28:33 来自手机 | 显示全部楼层
学习一下....

出0入0汤圆

发表于 2013-5-7 16:10:27 | 显示全部楼层
mark              

出0入0汤圆

发表于 2014-2-11 14:13:21 | 显示全部楼层
看来C还没入门啊~~

出0入0汤圆

发表于 2017-9-14 14:24:32 | 显示全部楼层
数据结构里面好像就有说到链表

出0入8汤圆

发表于 2018-10-26 15:17:02 | 显示全部楼层
不明觉厉

出0入0汤圆

发表于 2018-12-2 19:04:56 | 显示全部楼层
marker 一下,过后再看

出0入0汤圆

发表于 2018-12-2 19:16:34 来自手机 | 显示全部楼层
用过的人觉得不难,没有用过的觉得难
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-28 16:02

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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