AVR单片机c程序设计编程时常见的问题总结分析

发布者:素心轻语最新更新时间:2020-01-21 来源: elecfans关键字:AVR单片机  c程序设计  编程 手机看文章 扫描二维码
随时随地手机看文章

这两天在用AVR单片机做项目,这次是边做边深入学,尽量将以前忽略的知识用上,比如指针、文件包含、条件编译、变量作用域等一一调研清楚。收获不少,再次体会到学习的过程中没有无用的地方。用的越深入,才发现学时以为没用的东西都是最有用的,因为都被忽略了。幸亏学习时候的最重要的《c程序设计》如果不能解决,就找编译器的问题。这是这段时间总结的经验。

AVR单片机c程序设计编程时常见的问题总结分析


一、函数指针

1.int (*func)(void)--基本函数指针变量定义方式,变量func是一个指向返回值为int,没有参数的函数指针,这与其他变量定义有点区别,一般是把变量名放最后,如int a,而函数指针比较不直观,

2.typedef int(*ftype)(void); ftype func;--类型重定义方式,先定义一种新的类型ftype,它是一种指针类型,这种类型专门指向返回值为int,没有参数的函数,再通过该类型定义一个具体的变量func

3.func=functionName--函数指针赋值,funcTIonName为已经定义的函数的函数名

4.(*func)()--通过函数指针调用函数,也可以直接调用func(),

5.函数指针的一般作用:刚学函数指针的时候感觉没啥用,在接触操作系统以及一些消息、事件驱动的机制以后意识到它的意义。简单的讲如果希望在发生某种事件、中断等情况下不希望主程序再去查看、扫描做判断,而是自动执行某个功能函数时候,可以使用回调函数实现。如每次按下键盘都让某个灯亮,可以将亮灯的函数指针传递给按键中断函数,由中断内部自动调用。这是比较简单的应用,肯定可以直接用一个函数代替,但是一旦希望在执行过程中修改该消息、中断响应的操作的话,用函数指针就方便多了。在正常的程序执行过程中,调用方一般都是遇到函数就立即执行。而回调函数则是调用方通过函数指针的形式把函数储存起来。这样在合适的实际调用方就可以通过这个函数指针执行某个功能。回调函数可以说是一种订阅、分发的机制。被调用方可以通过订阅的形式将自己的处理函数以函数指针的形式交给调用方。当调用方需要执行这个回调函数的时候,就会通过分发的形式回调被调用方。回调函数的机制可以说无处不在,比如Channie Liu 所说的MFC消息机制,再比如HOOK,等等都是通过回调函数机制来执行的。但是回调函数并不是系统独有的机制。你完全可以在自己的程序中通过函数指针来实现一套回调函数。还有回调函数并不是面向对象编程,在某些情况下可以使用观察者模式来代替它。在.net中已经使用是事件的方式代替了回调函数来实现消息相应。


6.avr编程中要注意不是所有的编译器都能很好的支持函数指针,使用以及查资料发现ICCAVR7.1某个版本在编译后的代码进行仿真发现程序总是跑飞,查看汇编发现生成一个EIJMP指令(扩展间接跳转指令),后来尝试换用最新版7.21A版本,发现这个编译后就没这个指令,可以正常仿真了。同时CodeVision也有这个版本的问题。


二、头文件包含

以前一直以为对这个很理解,没太在意,虽然也犯了几次错误,但都没有深究,这次又复习了一下“谭浩强”发现还是有根本的误解的。在对头文件理解之前需要理解编译过程。编译是以源文件为单位,也就是*.c或*.c++等,生成的目标文件也是与源文件对应的。而头文件的作用是把可能公用的声明放在一起,被源文件包含后,在编译的过程中可以理解为直接加在源文件的内部,而且添加的顺序与源文件的include语句顺序对应。所以如果A.c包含B.h,而B.h又用到C.h内容,但B.h本身没包含则在A.c中要注意先包含C.h再包含B.h。另外就是变量的定义,即需要申请内存占用内存这样的语句不能放在可能被多处包含的头文件中,这样会引发多次定义的错误。这个问题我一直以为在头文件的开始和结尾有个#ifndef语句就万事大吉了,后来才知道不是那么回事。#ifndef语句只是为了在A包含B,A包含C,B包含C这样情况下阻止C被两次包含,而如果还有一个D也包含C的话那么A与D两个源文件编译后的代码中都会对C中的变量进行定义的,从而造成变量多次定义。


三、条件编译

这个没太多用过,直到最近想把单片机的程序写的更通用一些,尽量能抽象出来一些公用的函数,可以在各个硬件平台使用,免去不少的重复工作。如串口通讯在51下,在avr下都写过,但是每次都是现用现写,现在想尽量把每种功能硬件相关部分提炼出来,并压缩到最小。这里面就需要用到条件编译对各种平台进行判断,对每种功能进行控制。看过嵌入式linux内核的应该都发现这个特点了,那就是成篇的条件编译。


四、变量作用域

我最常犯的就是全局变量与静态变量的错误使用。具体可以看“谭浩强”,这里只说明一下常用的全局变量的使用。有时候希望一个公共变量能在各个源文件访问,或者作为某种信号、开关使用。就需要在某个源文件中定义,然后在其他需要用到的地方使用extern关键字。如果需要用的地方太多,就在头文件中使用extern声明该变量,在其他源文件中包含该头文件即可。

关键字:AVR单片机  c程序设计  编程 引用地址:AVR单片机c程序设计编程时常见的问题总结分析

上一篇:基于AVR单片机实现超声波测距的程序编写
下一篇:基于MSP430F135与DSl8820芯片设计煤矿瓦斯浓度无线监测系统

推荐阅读最新更新时间:2024-11-10 19:17

AVR 数码管编程
/***************************************** * 目 的:数码管动态扫描 * * 功 能:数码管显示 * * 时钟频率:内部1M * * 编译环境:ICC-AVR6.31 * * 实验环境:DOFLY mini80AVR开发板 * * 使用硬件:8位数码管 * * 结 果:8位数码管显示0-7 数字 * * 操作要求:插上J6跳帽 * *****************************************/ #include iom16v.h #include macros.h #define OE_138_ON PORTC |= BIT(7) //使能74hc138
[单片机]
STM32 Systick 编程及应用
提到systick 不得不抱怨以下STM32 的用户手册,既然提供了systick 的功能,为啥手册里却只提了一下?后来笔者上网搜的时候,才发现,抱怨的不仅仅是我一个人。闲话不说,下面将笔者搜集的资料进行总结。 一、 systick介绍 Systick 就是一个定时器而已,只是它放在了NVIC 中,主要的目的是为了给操作系统提供一个硬件上的中断(号称滴答中断)。没有学过操作系统的同学, 可能会很郁闷,啥叫滴答中断?这里来简单地解释一下:操作系统进行运转的时候,也会有 心跳 。它会根据 心跳 的节拍来工作,把整个时间段分成很多小小的时间片,每个任务每次只能运行一个 时间片 的时间长度就得退出给别的任务运行,这样可以确保任何一
[单片机]
超声波测距电路+汇编程
我现在在做超声波测距,用的是非门 + CX20106A方案。发射部分用非门驱动,如下: (原文件名:超声波发射电路原理图.gif) 我手上没有74ALS04或74LS04,所以用74HC04和HCF4069UBE代替。 超声波接收采用CX20106A,如下: (原文件名:接收电路 .jpg) 我用的CX20106A是拆机件。 用万用板搭好电路之后,在网上找到了一些参考汇编程序,我修改后可以通过串口发到PC显示超声波往返的时间: ;/////////////////////////////////////////////////////// ; USE BY :超声波测距器
[单片机]
超声波测距电路+汇<font color='red'>编程</font>序
STM32正交编码器编程
如图,STM32的每个TIMER都有正交编码器输入接口,TI1,TI2经过输入滤波,边沿检测产生TI1FP1,TI2FP2接到编码器模块,通过配置编码器的工作模式,即可以对编码器进行正向/反向计数。 如下图,编码器使用了A,B两相信号,但是我只需要对TI1信号进行计数(第一行),我也是刚发现了这个错误,原来对两个信号都计数,导致码盘转一周得到不止100个脉冲(100线的光电码盘)。通过STM32的编码器模块比较两想的电平信号就可以很容易地计算出编码器的运行情况了。 代码如下: void Decoder_Configuration(void) { GPIO_InitTypeDef GPIO_InitSt
[单片机]
STM32正交编码器<font color='red'>编程</font>
DSP编程技巧---不得不看的编译指示
编译指示(Pragma Directives)可能是所有的预处理指令中最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma指令对编译器给出了如何处理特定的函数、对象和代码段的方法,在保持与C/C++语言完全兼容的情况下,给出主机(比如C28x)或操作系统(比如DSP/BIOS)专有的特征。这些编译指示的使用较为复杂,但是我们还必须要了解它们,因为它们是程序中必不可少的东西,例如#pragma DATA_SECTION ( symbol , section name );这样的。但是往往讲解它们的资料又不多(因为大部分资料集中在入门指南上面),所以在此我们就总结一下针对C28x编译器的pragm
[嵌入式]
基于MSP430单片机编程器的设计
1.引言 单片机开发与应用已渗入我们生活中各个方面,其中一个应用就是对内存较小的芯片大批量烧录,就有了性能稳定的高速编程器诞生以满足各大厂商实现大量芯片烧录的目标。目前市场上运用最广泛的编程器是基于89C51的,但其功能过于单一,不能满足日益发展的市场需求。本文提出一种采用MSP430F149单片机作为CPU控制核心的编程器。与51单片机编程器相比,MSP430单片机编程器增加了I2C存储模块,可无需电脑利用该编程器对芯片进行烧录,使烧录过程更方便、快捷。 2.系统设计 基于MSP430的单片机编程器以MSP430F149为核心,主要由键盘、显示、串口、烧写、电平转换、电源和存储模块构成。系统结构框图如图1所示。 图1系统结
[单片机]
基于MSP430单片机<font color='red'>编程</font>器的设计
具可编程增益放大器的双通道宽带混频器可实现5G 无线接入
凌力尔特公司 (Linear Technology Corporation) 推出一款新宽带、高动态范围双通道混频器 LTC5566,该器件集成了可编程可变增益 IF 放大器。这款双通道混频器具非常宽的 300MHz 至 6GHz 输入频率范围,得到了专门优化,而且在新的 3.6GHz 和 4.5GHz 5G 频段以及已经使用很长时间的 4G 频段具广泛的表征。此外,该器件支持高达 400MHz 的带宽,以满足日益增多低于 6GHz 的 5G 无线接入设备的需求。这款双通道混频器提供了出色的动态范围,在 3.6GHz 时具 +11.5dBm 输入 P1dB 和 +25.5dBm 输入 IP3。在高达 5.8GHz 的较高频率时,其
[网络通信]
AVR单片机SPI口读写AT45DB161D接口程序设计
本程序为AVR单片机SPI口访问AT45DB161D提供一组接口函数,通过这一组接口函数可非常容易的完成对AT45DB161D的读写操作 AT45DB161D按页组织和操作(读写擦等等)内部的FLASH存储器,每页为528字节(特殊用途时可通过命令配置成512字节),其内部共集成4096页, 即4096*528=2162688字节。本程序将为您提供读写这2162688字节存储区的线性操作方法。使用这些函数,用户可不必考虑AT45DB161D内部的存储 器组织结构,如同读写一个文件一样进行读写操作。 void df_init(void); 这是SPI口初始化函数,它必须在所有这些接口函数调用之前得到调用 void df_re
[单片机]
<font color='red'>AVR单片机</font>SPI口读写AT45DB161D接口程序设计
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved