热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

avr用c语言编程出现bug,AVR c语言编程风格

AVRc语言编程风格出处:cfanandham发布于:2007-04-2911:08:16转载请注明出处,www.avrvi.comAVR

AVR c语言编程风格

出处:cfanandham 发布于:2007-04-29 11:08:16

转载请注明出处,www.avrvi.com AVR与虚拟仪器

作为一个初学者如何具有良好的程序设计风格呢?我想引用一个关于初学者请教编程大师的故事让读者自己去领悟。

有一位编程大师,他写非结构化的程序,一位初学者刻意模仿他,也写非结构化的程序。当他让大师看他的进步时,大师批评了他的非结构化程序:“ 对一位编程大师合适的东西未必对一个初学者同样合适,在超越结构化之前,你必须理解编程之道。” 我个人认为作为一个初学者应该踏踏实实的打好程序设计的基础,不要急功近利,舍本逐末。我走过不少弯路,希望大家能和我一样能牢记编程大师的忠告:“对编程大师合适的东西未必对一个初学者同样合适”。

本文所描述的编程风格适合于大部分语言,文章中可能提到你不是很了解的概念,没有关系,你放心的读下去,当你使用AVR一个月之后,你什么都明白了。

AVR c语言编程风格

文件结构

模块化的程序应该是有一个很好的程序结构的。AVR C语言程序有两种用户文件,.c程序文件,.h头文件,程序中编写过程中需要在.c文件中包含.h头文件。初学者往往出现重复包含或者头文件包含错误的问题,我当时也时常为这种错误而发愁。下面我以我写的电机驱动例程来给大家说明一下,的编程文件结构。

这个工程中有8个文件,一个说明文件,如下图:程序例子 电机控制 。

我写的成型的程序的文件个数基本上都是偶数,因为每一个结构化的函数定义.c文件都会对应一个.h文件。main.c对应config.h。我们来看看各文件的包含关系。下面我们看看这些文件的包含关系与内容:[推荐的文件包含顺序与关系]

所有.c文件都包含了config.h文件。如: #include "config.h"

在config.h 中有如下代码:

#include "delay.h"

#include "device_init.h"

#include "motor.h"

这样做就不容易出现错误的包含关系,为了预防万一,我们还引入了宏定义与预编译。如下:

#ifndef _UNIT_H__

#define _UNIT_H__ 1

//100us

extern void Delay100us(uint8 n);

//1s

extern void Delay1s(uint16 n); // n <&#61; 6 ,when n&#61;&#61;7, it is 1.

//1ms

extern void Delay1ms(uint16 n);

#endif

次包含本文件的时候正确编译&#xff0c;并且#define _UNIT_H__ 1&#xff0c;第二次包含本文件#ifndef _UNIT_H__就不再成立&#xff0c;跳过文件。

预编译还有更多的用途&#xff0c;比如可以根据不同的值编译不同的语句&#xff0c;如下&#xff1a;

//#pragma REGPARMS

#if CPU_TYPE &#61;&#61; M128

#include

#endif

#if CPU_TYPE &#61;&#61; M64

#include

#endif

#if CPU_TYPE &#61;&#61; M32

#include

#endif

#if CPU_TYPE &#61;&#61; M16

#include

#endif

#if CPU_TYPE &#61;&#61; M8

#include

#endif

#include 与 #include "filename" 的区别 &#xff1a;前者是包含系统目录include下 的文件&#xff0c;后者是包含程序目录下的文件。

变量名与函数名

变量以及函数命名应该按照尽量短&#xff0c;按需长&#xff0c;具有实际意义。可以通过下划线或者大小写结合的方法组合动词和名词组成变量函数名。下面对比好的命名方法与不好的命名方法&#xff1a;

好的&#xff1a; Delay100us();

不好的&#xff1a; Yanshi();

好的&#xff1a; init_devices();

不好的&#xff1a; Chengxuchushihua();

好的&#xff1a; int temp;

不好的&#xff1a; int dd;

外部调用

首先在模块化程序的.h文件中定义extern

//端口初始化

extern void port_init(void);

//T2初始化

void timer2_init(void);

//各种参数初始化

extern void init_devices(void);模块化程序的.c文件中定义函数&#xff0c;不要在模块化的程序中调用程序&#xff0c;及不要出现向timer2_init();这样函数的使用&#xff0c;因为你以后不知道你到底什么地方调用了函数&#xff0c;导致程序调试难度增加。可以在定义函数的过程中调用其他函数作为函数体。

/**************************采用timer2 产生波形***********************/

// PWM频率 &#61; 系统时钟频率/(分频系数*2*计数器上限值))

void timer2_init(void)

{

TCCR2 &#61; 0x00; //stop

TCNT2&#61; 0x01; //set count

OCR2 &#61; 0x66; //set compare

TCCR2 &#61; (1<

//占空比&#xff1d;高比低为&#xff1a;(OCR2-0X01)/(0XFF-OCR2) OX01&#43;&#43;&#43;&#43;&#43;&#43;(OCR2)__________OXFF (&#43;表示输出高&#xff0c;_表示输出低)

//即OCR2越大&#xff0c;输出越大

}在少数几个文件中调用函数&#xff0c;在main.c中调用大部分函数&#xff0c;在interupts.c中根据不同的中断调用服务函数。

void main(void)

{

/******************************************************************************/

//初始工作

/******************************************************************************/

init_devices();

while(1)

{

for_ward(0); //默认速度运转 正

Delay1s(5); //延时5s

motor_stop(); //停止

Delay1s(5); //延时5s

back_ward(0); //默认速度运转 反

Delay1s(5); //延时5s

speed_add(20); //加速

Delay1s(5); //延时5s

speed_subtract(20); //减速

Delay1s(5); //延时5s

}

}宏定义

宏定义主要用于两个地方&#xff1a;

一是用得非常多的命令或语句&#xff0c;利用宏将其简化。

#ifndef TRUE

#define TRUE 1

#endif

#ifndef FALSE

#define FALSE 0

#endif

#ifndef NULL

#define NULL 0

#endif

#define MIN(a,b) ((a

#define MAX(a,b) ((a>b)?(a):(b))

#define ABS(x) ((x>)?(x):(-x))

typedef unsigned char uint8; /* 定义可移植的无符号8位整数关键字 */

typedef signed char int8; /* 定义可移植的有符号8位整数关键字 */

typedef unsigned int uint16; /* 定义可移植的无符号16位整数关键字 */

typedef signed int int16; /* 定义可移植的有符号16位整数关键字 */

typedef unsigned long uint32; /* 定义可移植的无符号32位整数关键字 */

typedef signed long int32; /* 定义可移植的有符号32位整数关键字 */

二是利用宏定义方便的进行硬件接口操作&#xff0c;再程序需要修改时&#xff0c;只需要修改宏定义即可&#xff0c;而不需要满篇去找命令行&#xff0c;进行修改。

//PD4,PD5 电机方向控制 如果更改管脚控制电机方向&#xff0c;更改PORTD |&#61; 0x10即可。

#define moto_en1 PORTD |&#61; 0x10

#define moto_en2 PORTD |&#61; 0x20

#define moto_uen1 PORTD &&#61;~ 0x10

#define moto_uen2 PORTD &&#61;~ 0x20

//启动TC2定时比较和溢出

#define TC2_EN TIMSK |&#61; (<<1OCIE2)|(1<

//禁止TC2再定时比较和溢出

#define TC2_DIS TIMSK &&#61;~ (1<

为了增加程序的可读性&#xff0c;方便合作者读动程序&#xff0c;或者程序作者在一段时间之后还能看懂程序&#xff0c;我们需要在程序中写 注释。

在比较特殊的函数使用或者命令调用的地方加单行注释。使用方法为&#xff1a;

Tbuf_putchar(c,RTbuf); // 将数据加入到发送缓冲区并开中断

extern void Delay1s(uint16 n); // n <&#61; 6 ,when n&#61;&#61;7, it is 1. 在模块化的函数中使用详细段落注释&#xff1a;

/***********************

** 函数名称: Com_putchar

** 功能描述: 从串行口输出一个字符c

** 输 入: c:输出字符

** 输出 : 0:失败 1:成功

** 全局变量: 无

** 调用模块:

** 说明&#xff1a;

** 注意&#xff1a;

********************/

在文件头上加文件名&#xff0c;文件用途&#xff0c;作者&#xff0c;日期等信息。

/*********************************************************************************************************

** serial driver

** (c) Copyright 2005-2006, limaokui

** All Rights Reserved

**

** V1.1.0

**

**

**--------------文件信息--------------------------------------------------------------------------------

**文 件 名:sio.c

**创 建 人: 李茂奎

**修改日期: 2005年7月13日

**描 述: serial driver

**

**--------------历史版本信息----------------------------------------------------------------------------

** 创建人: 李茂奎

** 版 本: V1.00

** 日 期: 2005年7月13日

** 描 述: 原始版本

**

*********************************************************************************************************/

要清楚&#xff0c;注释是为了方便阅读&#xff0c;增强程序的可度性&#xff0c;不要本末倒置&#xff0c;不要给很简单大家都能看明白的程序加注释&#xff0c;不要让注释淹没了你的程序结构。对于函数&#xff0c;变量等尽量使用文件名自注释的方法&#xff0c;及通过文件名就可以知道意思。

:



推荐阅读
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 本文介绍了C函数ispunct()的用法及示例代码。ispunct()函数用于检查传递的字符是否是标点符号,如果是标点符号则返回非零值,否则返回零。示例代码演示了如何使用ispunct()函数来判断字符是否为标点符号。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 本文介绍了基于c语言的mcs51单片机定时器计数器的应用教程,包括定时器的设置和计数方法,以及中断函数的使用。同时介绍了定时器应用的举例,包括定时器中断函数的编写和频率值的计算方法。主函数中设置了T0模式和T1计数的初值,并开启了T0和T1的中断,最后启动了CPU中断。 ... [详细]
author-avatar
minggute_111
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有