查看: 2152|回复: 3

九天论道-谈单片机程序的编程风格

[复制链接]

该用户从未签到

发表于 2008-5-13 12:39:30 | 显示全部楼层 |阅读模式
分享到:
晚上整理另一个计算机里的资料,突然发现7年前和一个同事一起编写的文档和代码,已经过了保密期,不敢私藏,拿出一点共享大家。

通常写PC代码的人都非常注意编程风格和版本管理,大概是由于代码量复杂很多吧。原来我项目组里有个清华的研究生哥们,是我见过写代码最牛的了,经常是在linux下运指如飞,各种开发语言都会,最牛的是不要硬件平台就能写出几乎没有什么bug的代码,经测试人员在硬件平台上测试后运行很正常,令我大为佩服。
而写单片机代码的人大部分都不注意编程风格,通常都是比较自由散漫的风格,究其原因大概与单片机大部分是单兵作战有关,自己写成什么样子自己能看懂就行。其实不然,良好的风格不仅使代码具有良好的可维护性,让人读起来也是赏心悦目,更重要的是在进行多兵联合作战的情况下,良好统一的编程风格可以让调试变得更加简单,减少扯皮现象的发生,加快联调的进度。


由于所使用编译系统的特殊性,本文档包含一些软件设计中建议遵循的约定。本文档仅仅描述***系统软件中的底层接口功能模块,以及这些模块所应该提供的接口函数原型定义。

A.    约定:
1.    建议在所有的软件设计过程中,尽量使用标准C,不要使用汇编/C++等编程规则。

2.    在通常情况下,各类C编译器都没有定义标准的字节型(BYTE)、字型(WORD)、长字型(DWORD)数据类型,并且整型(int)、长整型(long)等数据类型所表示的字节数是不同的。所以,根据我们所使用的C编译器特点,自定义以下简单数据类型:
无符号字节型(UCHAR)、无符号字型(UWORD)、无符号长字型(ULONG)、
有符号字节型(SCHAR)、有符号字型(SWORD)、有符号长字型(SLONG)
建议在软件设计过程中尽量使用自定义数据类型。这些自定义简单数据类型定义如下(包含在DataType.h中):
#ifndef __DATATYPE__
#define __DATATYPE__

typedef unsigned char UCHAR;
typedef char SCHAR;
typedef unsigned short UWORD;
typedef short SWORD;
typedef unsigned long ULONG;
typedef long SLONG;

#endif

3.    变量和宏的命名规则遵循标准C的命名规则。变量的命名用英文单词的全拼表示,各单词之间用下划线分隔,并且每个单词的第1个字母大写;宏的命名也用英文单词的全拼表示,各单词之间不用下划线分隔,并且每个单词的每个字母均大写。例如:    UWORD    Song_Name            ;定义一个无符号短整型变量
#define    TOTALNUMBER    20    ;定义一个宏TOTALNUMBER

4.    结构和联合等复合变量的命名规则同变量类似,只是每个单词的每个字母均大写。如:
// 结构定义
typedef struct _STRUCT_DEFINITION
{
    UCHAR ch;
} STRUCT_DEFINITION;

// 变量定义
STRUCT_DEFINITION        Str_Def;

5.    函数的命名规则同变量。形参的命名同变量类似,只是单词的每个字母均小写。
例如:void Get_Song(UCHAR  song_name[11],ULONG *buffer, ULONG length)

6.    一般情况下,所有模块文件内的注释均采用英文书写。

7.    定义函数操作返回值常量:成功:SUCCESS 错误:FAILED

8.    系统定义所有寄存器和寄存器操作宏:
i.    寄存器定义,如:
#define        SCR        0xFFFFF000
建议不要直接使用寄存器定义,而是使用以下宏定义
ii.    获取寄存器操作宏,在寄存器名称前加GET_前缀,如:
#define        GET_SCR    *((UCHAR *) SCR)
使用: UCHAR xx = GET_SCR;
iii.    设置寄存器值操作宏,在寄存器名称前加SET_前缀,如:
#define        SET_SCR(rVal)    *((UCHAR *) SCR) = (UCHAR) rVal
使用: SET_SCR(0x18);

9.    每个模块文件内书写约定:
i.    文件头:
本部分包含模块简要描述,具体内容如下:
1.    模块名称(Module Name)
2.    模块编制者(Author)
3.    模块版本(Version)
4.    模块编制日期(Create Date)
5.    模块描述(Description)
6.    模块特殊声明(Remark)
7.    模块修改历史(Revision History)
ii.    接口定义:
本部分包含模块内所有函数的接口定义,每个函数具体定义如下:
1.    函数原型(Prototype)
2.    函数功能描述(Description)
3.    函数入口(Input)
4.    函数出口(Output)
5.    函数特殊声明(Remark)

iii.    全局变量和宏定义:
本部分声明本模块使用的全局变量和宏定义
iv.    具体算法描述:
本部分具体实现所有函数的算法
v.    模块测试规划:
本部分描述本模块内所有函数功能的测试方法和注意事项

eg.
    Zip控制(ATAPI命令封装接口函数)模块        模块
本模块完成系统使用的Zip控制相关的所有ATAPI接口命令的封装。

1.    本模块常量、数据结构以及特殊约定描述:
2.    接口描述:
a)    传递Zip控制:
函数原型:SWORD    Pass_Zip_Control(UCHAR *buf, UWORD len);
功能描述:USB传递控制/数据到Zip
函数入口:buf:传递数据缓冲区
len:传递数据实际字节数
函数出口:FAILED:未知错误
          SUCCESS:传递成功
          其它非零值:发生错误需要回传的数据字节数,数据存放在
缓冲区buf
特殊声明:无

以下略。。。
回复

使用道具 举报

该用户从未签到

 楼主| 发表于 2008-5-13 12:40:15 | 显示全部楼层

RE:九天论道-谈单片机程序的编程风格

一个通过ATAPI接口控制磁盘的例子
硬件使用的是motorola的dragonball系列vz328

/*********************************************************************
**    Module Name:        atapi_oem.c                                    **
**    Author:                Huozq                                        **
**    Version:            1.0                                            **
**    CreateDate:            2001-06-14                                    **
**    Description:        Atapi Functions                                **
**    Remark:                                                            **
**    Revision History:    2001-06-14                                    **
**********************************************************************/

#include    "Atapi_OEM_Data.h"
#include    "VZ328_Register_Definition.h"
#include     "DataType.h"

//Invoke example
//Before operate(read or write) the drive it should check the status of zip
//{
//        while( errno = Packet_Drive_Ready() ) ;
//        Packet_Read(i*256,0,buf);   
//}

void  Zip_Initialize(void)
{
    // Port initialization
    SET_PCSEL (0xff);
    SET_PCDIR (0xff);
    SET_PCPUEN(0xff);
    SET_PDSEL (0xff);
    SET_PDDIR (0xff);
    SET_PDPUEN(0xff);
    SET_PKSEL (0xfb);                        
    SET_PKDIR (0x7f);                        
    SET_PKPUEN(0xff);
    SET_PMSEL (GET_PMSEL | 0x20);
    SET_PMDIR (0xff);                        
    SET_PMPUEN(0xff);
    // Other initialization
    SET_PKDATA(0x7f);
    SET_PMDATA(GET_PMDATA | 0x20);
}
//Read the content of registers,Used for test
void Read_Register(void)
{
    UWORD    i,status,addr;
   
    SET_INPUT_MODE();
    for(i=0;iBuffer_Pointer;
        
    Packet();
    Send_Packet( (UWORD *)ptrATAPI-&gtacket_Command);
   
    if ( ptrATAPI->Id == ID_WR )                    //If write operation
    {
        if ( (ptrATAPI-&gtacket_Command[0] = 0x0a) && (ptrATAPI->Buffer_Length == 0) )
            ptrATAPI->Buffer_Length=256;
        n=ptrATAPI->Buffer_Length;
        for (i = 0; i < n; i++)
        {
               SET_INPUT_MODE();
               while ((status = Read_ATA_Reg(STATUS_REG)) & ATA_STATUS_BSY) ;
            if (status & ATA_STATUS_ERR)
            {
                    errno = Read_ATA_Reg(ERROR_REG);
                    return    errno;
            }                                        //check the status
        
            SET_OUTPUT_MODE();
            SET_ADDR(DATA_REG);
               for (j = 0; j < 256; j++)
               {
                //Write_A_Word( buf[i * 256 + j] );
                Write_A_Word( *buf++ );
                ASSERT_WR();
                NEGATE_WR();                        //write
            }
        }
    }
    else if ( ptrATAPI->Id == ID_RD )                //If read operation
    {
        if ( (ptrATAPI-&gtacket_Command[0] = 0x08) && (ptrATAPI->Buffer_Length == 0) )
            ptrATAPI->Buffer_Length=256;
        n=ptrATAPI->Buffer_Length;
        for (i = 0; i < n; i++)
           {
                  while ((status = Read_ATA_Reg(STATUS_REG)) & ATA_STATUS_BSY) ;
            if (status & ATA_STATUS_ERR)
               {
                errno = Read_ATA_Reg(ERROR_REG);
                   return    errno;
            }
           
               SET_ADDR(DATA_REG);
            for (j = 0; j < 256; j++)
                  {
                ASSERT_RD();
                   *buf++ = Read_A_Word();
                   //buf[i * 256 + j] = Read_A_Word();
                   NEGATE_RD();
               }
           }
    }
    else if ( ptrATAPI->Id == ID_SET )
    {
        while ((status = Read_ATA_Reg(STATUS_REG)) & ATA_STATUS_BSY) ;
        if (status & ATA_STATUS_ERR)
        {
            errno = Read_ATA_Reg(ERROR_REG);
            return    errno;
        }                                            
   
        SET_OUTPUT_MODE();
        SET_ADDR(DATA_REG);
        for (j = 0; j < (UWORD)( ptrATAPI->Buffer_Length / 2 ); j++)
        {
            Write_A_Word( buf[j] );
            ASSERT_WR();
            NEGATE_WR();                           
        }
    }
    else                                            //If other operation
    {
        while ((status = Read_ATA_Reg(STATUS_REG)) & ATA_STATUS_BSY) ;
        if (status & ATA_STATUS_ERR)
        {
            errno = Read_ATA_Reg(ERROR_REG);
            return    errno;
        }                                            
        SET_ADDR(DATA_REG);
        for (j = 0; j < (UWORD)( ptrATAPI->Buffer_Length / 2 ); j++)
        {
               ASSERT_RD();
               buf[j] = Read_A_Word();
               NEGATE_RD();
        }
    }
   
    SET_INPUT_MODE();
    return 0;
}

void Send_Packet(UWORD *command)
{
    UWORD    i;
   
    SET_OUTPUT_MODE();
   
    for(i=0;i
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2008-5-13 12:40:49 | 显示全部楼层

RE:九天论道-谈单片机程序的编程风格

在底层函数基础上FAT16的实现,可惜有些功能没完全实现
/*********************************************************************
**    Module Name:        efat.c                                        **
**    Author:                Huozq                                        **
**    Version:            1.0                                            **
**    CreateDate:            2001-07-15                                    **
**    Description:        Encapsolution similar file system            **
**    Remark:                                                            **
**    Revision History:    2001-07-15                                    **
**********************************************************************/
#include "..\include\DataType.h"
#include "..\include\Fat16.h"
#include "..\include\Atapi_OEM_Data.h"

//May be for public use
void e_strcpy(UCHAR *s, UCHAR *d);
void e_strncpy(UCHAR *s, UCHAR *d, UWORD l);
SWORD e_strcmp(UCHAR *s, UCHAR *d);
typedef struct
{
    UWORD   Bytes_Per_Sector;
    UWORD   Sectors_Per_Cluster;
    UWORD   FAT_Number;
    UWORD   Root_Item_Number;
    UWORD   Sectors_Per_FAT;
}    DISK_PARAMETER;
DISK_PARAMETER Disk_Parameter;

//Store file parameter
UCHAR Para_Buffer[512];

/*****************************************************************************
**    Prototype:        SWORD Get_Disk_Information(DISK_INFORMATION *ptrInfor);    **
**    Description:    Get the information of the disk                            **
**    Input Parameter:ptrInfor--The information about the disk                **
**    Return:            Error Code                                                **
******************************************************************************/
SWORD Get_Disk_Information(DISK_INFORMATION *ptrInfor)
{
    UWORD    errno,i;
    UCHAR     filename[12];
    UCHAR    *buffer;
   
    //Read the information of index
    while( errno = Packet_Drive_Ready() ) ;
    if( errno = Packet_Read(0,1,Para_Buffer) )    return errno;
   
    //Point to the head of Para_Buffer
    buffer=Para_Buffer;
   
    //Sum the total file number and total song number
    ptrInfor->Total_Song_Number = *(buffer+1);
    ptrInfor->Total_File_Number = *(buffer+1);
   
    //Locate to file information
    buffer+=0x20;
    buffer+=0x04;
    //Get the file name and length
    for( i=0; i< ptrInfor->Total_Song_Number; i++,buffer+=8 )
    {
        e_strcpy( (UCHAR *)"EWORLD",filename);
        filename[6]=i+1+0x30;
        e_strcpy( (UCHAR *)".DEC",filename+7);
        e_strcpy(filename,ptrInfor->Song_Infor.Song_Name);
        ptrInfor->Song_Infor.Song_Length=    \
            (*(buffer+1))
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2008-5-13 12:41:16 | 显示全部楼层

RE:九天论道-谈单片机程序的编程风格

一些宏定义,摘部分
#ifndef __DATATYPE_H__
#define __DATATYPE_H__
/* Simple Data Types Definitions */
typedef unsigned char UCHAR;
typedef char SCHAR;
typedef unsigned short UWORD;
typedef short SWORD;
typedef unsigned long ULONG;
typedef long SLONG;

/*********************************************************************
**    Module Name:        Fat16.h                                           **
**    Author:                Huozq                                        **
**    Version:            1.0                                            **
**    CreateDate:            2001-05-25                                    **
**    Description:                                                    **
**    Remark:                                                            **
**    Revision History:    2001-05-25                                    **
**********************************************************************/
#include "DataType.h"

#ifndef __FAT16__
#define __FAT16__

#define    BUFFER            0x10000
#define    BUFFER2            0x28000

#define    PART_SECTORS    32
#define LEN_ALL            187
#define FILE_NOT_FOUND    1
//CURRENT_SONG_INFOMATION    Current_Song_Information;   

//Function declaration
SWORD Get_Disk_Information(DISK_INFORMATION *ptrInfor);
ULONG Read_Song(UCHAR song_name[12], ULONG offset, ULONG length, UCHAR *buffer );
ULONG Write_Song(UCHAR song_name[12], ULONG offset, ULONG length, UCHAR *buffer );
SWORD Delete_Song(UCHAR  song_name[12]);
SWORD Delete_Part_Of_Song(UCHAR song_name[12],UWORD start_offset,UWORD end_offset);
void change_file_name(UCHAR *s);
void extend_file_name(UCHAR *s);
ULONG Get_Free_Space(void);
void Seek_Song(UCHAR song_name[12], ULONG offset);
#endif
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /2 下一条



手机版|小黑屋|与非网

GMT+8, 2024-12-27 14:14 , Processed in 0.164172 second(s), 21 queries , MemCache On.

ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

苏公网安备 32059002001037号

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.