版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
目录在程序中FLASH程器avr-gcc第三章GCCC第四章AVRAT989S52ispTWIavr-libcBootLoaderBootLoader第十章C++语言支持1avr-gcc附录2InHEX文件格式描 2000年在学校我第一次接触Linux,那时在班里学习做网页的气氛较浓,我也是为了PHP才认识Linux的。PHP解析器的安装过程让我多多少少对GCC有了些认识,不过当时我并没有它还可以用于嵌入式系统编程至于Linux为用处只在于架构一个免费的WEB站点。2002年在公司我第一次接触了AVR,当时公司只有一个ICC序列我在浏览双龙的数据光盘时发现一个叫“如何使用AVR-GCC”的PDF文档,上面没有署名,我应该感谢该文的作者。我发现这个免费的编译软件远比ICC好用。今天,我把使用AVR-GCC两年来的体会写在这里,愿的人了解和使用GCC及自由软件。水平有限,错误和缺陷在所难免,请广大读者批评指作者:芯2004-12-于内包5:所有的请注明出6第一章AVR单片机GCC开发概1997ATMEL公司挪威设计中心的A先生和V先生出于市场需求的考虑推出了全新配置的8位精减指令集微处理器(RISC-ReducedInstrctionSotCPU。起名为AVR。而T90S8515151T90S系列的绝部分已产,当一个T90S列产时TMEL通常会在TMega或Ttnyn2313作为T90s231T90S2313TMega855和ATMea8535分别作为AT0S8515AT90S855MegaATMega48/88/168、ATMega8、ATMega16、ATMega32、ATMega64ATMega128是ATMega系列的主品。值得关注的是ATMega8这一款单片机,它以丰富的片内资源、作为它的兼容产品,为用户提供功能的选择。ATMega16也是个用量较多的器件,它的引脚兼容AT90S8535,可以取代产品中的随着国内AVR用户的增多,ATMEL也开始了主流器件的中文翻译工作。从网络器件的翻译中文。这对学习和使用AVR器件提供了很大的帮助。IARC、WINAVR、ICCA、、-AVR(BASIC语到上万元。ICCAVR是国内AVR主要推广单位双龙公司的C编译器,它价格低XX,友好的界面把很多烦琐的项目管理和编译设置隐藏了起来,为此它受部分WinavrAVRGCCC/C++编译器。下面所1有章节我都会介绍如何使用WINAVR开发AVR单片机。学习GCC的意义绝不仅仅是为了开发AVR程序,正如21ICBBS上一位网友果其它编译器是一棵树,那么GCC就是个树林”,GCC支持多种处理器,包ARM、DSP、X8632CPU。它的历史足以说如果不是个业余的程序开发人员,我不会建议你使用BASIC编写AVR程序,因为我们程序的,而C更适合我们去这样做。GCCUNIXCCC(CCompilerC编译器GNUC编译器GCC(GNUCCompiler然而,随GCC支持语言GCC这个缩写的意义已演GNU编译器集合(GNUCompilerCollection)GNU项目的一个产品,是个开是它们中间的产物。GCC这样的设计使得任何一种语言只要通过合适的语法解析器产生符任何一种器件只要将树结构翻译成汇编,就可以使用GCC前端所支持的所有语言。上前端和后端都不是孤立的。幸运的是AVR的确得到了GCC的支持,它也是GCC支持的唯一一种8位处理器。不仅如此,我们还可以在WINDOWS平台上安装程序包WINAVR来使用GCC的AVRC/C++编译程序。GNUGCCCC++AVR-里不一一列出,请参考WINAVR说明文档。WINAVR项目的WEB地址是,这里可以的版本,并可订阅邮件组。邮件组是获取WINAVR相关帮助信息的重要途径。2一个简单的文件demo1.c:#include#includeintmain(void{unsignedchar while{for(i=0;i<255;i++)}}PB0LEDdemo1.c,我们就可以编译它了。通过点击菜单开始->运行在弹出的框中输入“command”,来打开控 MCU类型,这是我们通过命令行选项-mmcu来指定的,我们指定的器件为at90s2313。-c选项告诉编译器编译完成后不连接。1-13 新生成了一个文件:demo1.o,它是我们的目标文件,我们再使 之后我们会在工作看见连接器生成的demo1.elf。gcc的连接后生成的文件为ELF格式,在命令行我们通常用.elf指定其扩展名。ELF格式文件除了包含不同器的二进制格avr-objcopy来提取单片机 - - -O gcc把不同类型的数据分到不同的段落,相关程序器的段有.text和.data,我们用选项–j指定了要提取的段。选项–O用来指定输出格式,这里我们指定为ihex(inHEX到此我们得到了最终可以写入单片机90S2313FLASH器的demo1.hex文件。用编程器将demo1.hex内容写入到单片机,便可看到接在PB0口的LED不断的闪烁。以上对一次编译过程的描述只是为了说gcc编译一C源程序际的应用中我管理工具来进行编译操作。Make由下一节介绍。4用MAKEFILE管理项其中项目管理器负责为每一个源程序文件调用编译器生成目标文件后用连接器将它们lusonobj(Hexln1WINAVRKeiluVisionIDE,所以我们需要写一个叫做可执行文件make.exe负责解析它并根据内容来调用编译器、连接器或其它的工具,最makeMakeMake[-ffilename] 方括号表示括号里边的内容可以省略filename代表make所使用的项目描述文件,如果此项省略,则从当前下按下列顺序寻找默认的项目描述文件 (当然、在WINDOWS下不份大小写文件名,也就无所谓了namesmakemakefile文件中遇了解makefile内容是非常有用的,但这不是必需的,因为WINAVR中一个小工具Mfile可以为我们生成功能够用的makefile样本。所以如果对makefile不太感,可以跳make命令引入了目标(targets)的概念。Makefile描述文件便是它的第一个目标,make命前下敲入make一样,make会输出以下的结果:5MAKE:***Notargetsspecifiedandnomakefile #Endall:便是第一个目标@echo@echo@echo#EndD:\AVRGCC\TEST>makeD:\AVRGCC\TEST>make由于在命令行明确指定了要执行的目标(two),makemakefile中找到指定的目标, makethree makethreeonetwo6 makefile文件按如下格式指定依赖关系:[命令 one:Two@echoone.@echotwo.#EndmakefileMakeoneoneTwoTwo后才执行one中令。三.Makefile命%.o:%.o: - %.o和%.c“%”代表任意的字符串,而7make–r可取消所有的隐含规则。例如对于C程序%.o可以自动的从%.c通过命令$(CC)c$(CPPFLAGS)$(CFLAGS)'生成。变量是在 CCCC=avr-%.o: - 字符‘#’开头的行为注释行,如果注释需要换行需在行尾加‘\’,除包含其它MAKEFIEL外在行的任意处可插入注释。 : 仅在目标是存档文件的成员时起作用,代表目标。如目标foo.a(bar.o)中$@foo.a$%代表bar.o 8 利用它我们可方便的生成合适的makefile。《Outputformat 《OptimizationleaveC代码的优化级,s《C/Csourcefile(s)Assemblersourcefiles(s)C、C++、1-2mfile件,这时只需在生成makefile中SRC变量后列出源文件名即可。Mfile生成的makefile有四个目标all:编译程序生成可执行文件。这也是默认的目标,即在命令行当前 任何选项的make命令将执行这一目标。9clean:在当 coffELFAVRStudio3.xAVRCOFFextcoffELFAVRStudio4.07COFF另外,C“.s后的目标指示将生成该源文件编译后的汇编代码文件(以“.s”结尾。开发环境的UltraEditC代码的高亮显示、项目管理及外部工具配置等功UltraEdit的个性化设置:高级->配置->编辑制表符宽度值和缩进空格娄均设成4。高级->配置->视图->查看列表选中函数列表 UltraEdit写主程序文件保存到此文件夹中这里设为demo.cUltraEdit创建一项目,负责管理文件项目->新建项目d:\devdir输入项目名称(prj)在接下来的文件设置框中的项目文件区输入或选择d:\devdir选中相对路径复选按钮(3)UltraEditmake我的项目高级->工具配置在工 区输入此你就可以在UltraEdit内就可以make你的程序了记得要在你的项目里添加源程序时,除了在UltraEdit项目->makefileSRC变量后列出来才可编译哦1-3UltraEditSI-Prog+PonyProg实现最廉价的实验AVR系列单片机提供对程序器(FLASH)和数据器(EEPROM)的串行编程功能(ISP,使它的程序烧写变得方便。AVR系列器件内部FLASH器的编程ISPI/O端口(MOSI、MISOSCK)与外部编程逻辑通信,编程入到FLASH或EEPROM。方便(只需几个分立元件、接线少(通过PC9针串行口编程) 可到ht 1-4SI-Prog想此方案的成本和一个AVR能烧写的次数,是不是觉得很值CA-171-CA-M88码开关将板上功能电路与ATMEGA8I/O引脚隔使用板1-1ATMEGA81-1CA-M8ATMEGA8I/OS6-S6-S6-S6-S6-S6-S6-S6-S5-S5-SI_ProgS5-S5-S5-S5-S5-S5-S1-S1-S1-S1-S1-S1-S1-S1-外部低频晶振(32768HzS6-3S6-4使用板上SI_Prog程序时应当将S5-1~S5-4开通。上位机软件建议使1-6PonyProg20041-7CA-M8的示例程序或CA-M8请到或.这里有关于CA- 312 312161514131211109161514131211109543211PC6(RST)PC5(ADC5/SCL)PD0(RXD)PC4(ADC4/SDA) PB7(XT2/TS2)PB5(SCK) PD6(AIN0)PB3(MOSI/OC2)PD7(AIN1)PB2(OC1B/SS) 23456789LED_Y
12345678123456781234SR_SERSR_RCKSR_SCK89C
RST
++
ERS
162
RS-232TO
B 10 R2in 938
976549765432197654321
5435432154321 9999
ee73245897324589 g gfbg
c6c66 第二章器操AVR单片机器组织结器、内部SRAM数据器和EEPROM数据器。Flash器为1K~128K字节,支持并行编程和串行, 由于AVR指令都为16位或32位,程序计数器对它按字进行寻址,因此FLASH器按字组织的,但在程序中FLASH区时指令LPM可分别指定地址的高低字(R0~R31作使用与内部SRAM同样的指令。其组织结构如图2-1所示。内部SRAM。外部SRAM被编址到内部SRAM后。组织。擦写可达100,000次。I/O寄存器#include#includeio.havrAVR各器件间存在同名寄存器地址有不同的问题,io.hSFR–mmcu选项再包含合适的ioxxxx.h文件。的方式读写SFR,如:可以在io2313.h中找到PORTB的定义如下:#define#define #define#define_SFR_IO8(io_addr)_MMIO_BYTE((io_addr)+#define_MMIO_BYTE(mem_addr)(*(volatileuint8_t这样,PORTB0XFF;就等同于*(volatileunsignedchar*)(0x380xff;0x38正是寄PORTB在器AT90S2313中是的地址。这进一步说明SFRSRAM操作的相同之处。在C程序中我们可以将符号PORTB看作是绑定到寄存器PORTB的变量。_BV(bitI/O寄存器时频繁用到的,avr-libc建议使用这一宏进行寄存器的位操作,它在文件sfr_defs.h中定义如下: (1<< //io.h中定义PB0: PB1: DDRB=0X03;DDRB=0X03;同样SRAM内变量的在C程序中一个没有其它属性(arrribute)修饰的全局或静态变量将被指定到内部SRAM,转换成全局的符号,这些符号标识了内部SRAM地址,而局部变量没有这种符号。 #include 1-12-24 48-9.22*10^18~-8在程序中FLASH程序#include#include<avr/pgmspace.h中它被定义成符号PROGMEM。
数据类型变量名 值charchar PROGMEM=1 PROGMEM=1;long PROGMEM=1对于不同长度的整数类型avr-libc提供对应的函数pgm_read_byte(prog_void*addr)pgm_read-word(prg_void*addr)另外在pgmspace.h中定义的8位整数类型 prog_uchar分别指定在charchar//ram flash_val1;flashvoid{…} // RROGMEM=unsigendcharI,ram_val;for(I=0unsigendcharI,ram_val;for(I=0I<10I循环{ram_val=pgm_read_byte(flash_array+ } PROGMEM PROGMEM= o, o,#include<avr/io.h>#include#include<avr/io.h>#include<avr/pgmspace.h>#include<stdio.h> flash_str1PROGMEM=全局定义字符串”;intmain(void){int{}}EEPROM数据器操#include eeprom_read_byte(constuint8_t*addr) eeprom_read_word(constuint16_t*addr) eeprom_read_block(void*buf,constvoid*addr,size_tn) eeprom_write_byte(uint8_t*addr,uint8_tval) eeprom_write_word(uint16_t*addr,uint16_tval) eeprom_write_block(constvoid*buf,void*addr,size_tn) 000RAM#include<avr/io.h>int{unsignedchar //等待EEPROM读写就绪eeprom_write_byte(0,0xaa);//0xaaEEPORM0地址处 }#include<avr/io.h>#include<avr/eeprom.h>#include<avr/io.h>#include<avr/eeprom.h>unsignedcharval1attributeint{unsignedchareeprom_write_byte(&val1,0xAA);val2=//写//读}数据在EEPROM中的具置是不透明的。文件中提取并产生ihex或binary等格式的文件,从而可以使用编程器或线将其写入到切。它会自动生成以“.eep”为后缀的文件,通常它是iHex格式。avr-gcc段(section)与再定位粗略的讲,一个段代表一无缝隙的数据块(地址范围),一个段里的数据都为同一性质,如“只读”数据。as汇编器)0地址开始,并生成目标文件。ld将这些数据块正确移动到它们运行时的地址。此过程非常严格,数据的内部顺序与长段、.bss段和.eeprom段,它们包括了程序器(FLASH)代码,内部RAM数据,和(LASHEEPROM器的使用量,关系如下:程序器(FLASH)使用 =.text+数据器(RAM)使用 =.data+.bss[+.noinit]+stack[+EEPROM器使用 =一..text.text段包含程序实际执行代码。另外,此段还包含.initN和.finiN两种段,下面详细讨段.initN和段.finiN是个程序块,它不会象函数那样返回,所以汇编或C程序不能调用。.initN、.finN和绝对段(absolutesection提供中断向量)avr-libc应用程序运行框.initN此类段包含从复位到main()函数开始执行之间的启动(startup)代码。此段绑定到函数init()。用户可重载init()将栈指针初始化成器件对应RAMEND处, .data,avr-libc应用程序运行框架是以静态库的形式在<winavr安装 .finiN09个,fini9fini1CC++用户代码插入到.initN或的,如下是一段插入到.init1段的示例:voidmy_init_portb(void)voidmy_init_portb(void)attribute((naked))\attribute((section(".init1")));voidmy_init_portb{PORTB=0xff;}使用arrribute关键字为函数指定属性要在函数的原型上,而不是函数的实现例程里。由于属性section(“.init1”)的指定,编译后函数my_init_portb生成的代码自动插入到.init1main函数前就得到执行。naked属性确保编译后该函数不生成返回指令,二..data.data段包含程序中被初始化的RAM区全局或静态变量。而对于FLASH器此段包含在程序中定义变量的初始化数据。类似如下的代码将生成.data段数据。charerr_str[]=”Yourprogramhasdiedahorribledeath!”;structpointpt={1,1};可以将.data在SRAM内的开始地址指定给连接器,这是通过给avr-gcc-Wl,-Tdata,addraddr0X800000SRAM将.data段从0x1100开始,则addr要给出0X801100。三..bss另外,.bss.noinit若变量被指定到.noinitstartup过程中不会被。将变量指定到.noinit段的方法如下:intintfoo ((sectionintintfolattribute#include#includeunsignedcharrstflag[5]attributeintint{unsignedcharj;{}{}{}…}四..eepromstaticunsignedchareep_buffer[3]staticunsignedchareep_buffer[3]attribute在连接选项中可指定段的开始地址,如下的选项将.noinit段指定位到RAM Avr-gccFLASH、RAMEEPROM内的段在一个统一的地址空间内处理,flash器被定位到0地址开始处,RAM器被定位到0x800000开始处,eeprom器被定位到0X810000处。所以在指定段开始地址时若是RAM内的段或eeprom内的段时要在实际器地址前分别加上0x800000和0X810000。voidvoidMySection(void)attribute((section(".mysection")));voidMySection(void){ o}外部RAM的使AT90S8515AVR器件RAM,使RAM需置位MCUCRSRE(SRAM号,型的地址、数据复用端口的时序操作。可参考51系列总线相关资料。堆应动态内存分配和堆几乎是同等概念,在局部使用大量的内存时我们通常会使用它,avr-libc提供两个标准函数malloc和支持动态内存分配。有三个全局变量将约束malloc的操作,它们分是malloc_heap_start、malloc_heap_end和malloc_margin。malloc_heap_startmalloc_heap_endmalloc在没用户干预GCCRAM应用规划RAM的开始处分配.data段,之后是.bss段,栈指针指向内部RAM最顶端,而堆从.bss的结束处开始,也就是说malloc_heap_start被初始化成.bss段结尾地址。malloc_heap_end被初始化成0,这时malloc函数分配内存时总和当前栈指针保持malloc_margin个字节距离,malloc_margin被初始化成32。显然,尽管有这种保护机智,过多的局部变量或过多的函数嵌套会导致堆用堆的方式使用外部RAM是个很好的主意,这时在连接时或运行时设置malloc_heap_start malloc_heap_end连接时的配置方式如下avr-gccavr-gcc...-Wl,--defsym=heap_start=0x802000,--defsym=heap_end=0x803fff可以在运行时直接赋值给malloc_heap_start和malloc_heap_endRAM#include<avr/io.h>#include<stdio.h>#includecharintusart_putchar(char{return}int{returnUDR;}void{//UART初始化UBRRL=25;//9600baud6MHz:38 }int{inti;charc; {{}printf("分配内存失败}}2-2GCCC编译CC语言书所描述。但出于很多C语言书讲的不够直接的现状,还是要简单的介绍一下。,对于初学者一定一.C“.cGCCCC源程序的文本文件。它们C编译器后生成以.o为扩展名的目标文件,用于生成最终的可执行文件。头文件扩展名为“.h”,编译器不会专门编译此文件而生成相应的目标文件。头文件的内容通常是函数原型或预处理宏定义。头文件通常使用预处理宏#include包含到源文件中。如:#include“uart.h”句中使用尖括号时预处理器会从编译器指定的包含中查找该文件。而使用引号时预处理器先从当前(包括源文件所在)二.两种CC程序中调用一个函数时编译器会根据函数的原型将参数指派到规定的寄存器或压intmax(itnpar1,intint{int……………}intmax(intpar1,int{ par1>par2?}在编译main函数不需要知道max是如何需要max的原型用于生成调用代码。为此必须在调用之前函数max的原型。当然,如果该函数的实现代码externint指示了一个数据类型为int的全局变量g_variable已在其它源文件中定义。 示相关的函数放在disy.c中,把UART通信相关的函数放在uart.c中,之后在包口函数main的文件demo.c中调用上述两个源文件所实现的函数。这是完全可能的,也是必须这样函数原型和外部变量使得C程序的模块化成为了可能,它们是C程序从多个#include#include {}#include#includeuchar{}#include“uart.h”#include“uart.h”int{ucharc;{ }}主程序main调用了disply.c和uart.c中的函数DisyNumber和UartRecvByte。它的UART接收一字节后显示到数码管上。你必须现在就知道我是在举例,实际上如那么在demo.c中DisyNumber和UartRecvByte的在哪儿呢?通常我们会把放到与源文件同名的.h文件中。这样我们就不用在每一个使用函数的源文件中都要,而只需使用#inlcude命令将头文件包含即可。Uart.h和Disy.h的内容分别如下 #include“common.h” DIS #includevoidDis #ifndef#ifndefCOMMON_H#define#include#defineucharunsignedcommon.hAVRio.h,还定义了在项目uchardisply.huart.h都包含了此文件demo.c将它们两包含进来后会不会导致在demo.c中两次包含common.c,定义两次的uchar而产生错误呢?C程序头文件通常使用一种预处理宏的技术来保证它在某个源文件中#ifndef和#endifdemo.cdemo.ccommon.h时由于符号COMMON_H未定义,#ifndef条件满足,中间内容便自动插入到demo.c中,同时符号COMMON_H#includecommon.h”时#ifndef这个条件将不avr-gcc–mmcu=atmega8–cdis avr-gcc–mmcu=atmega8–cdis avr-gcc–mmcu=atmega8–cuart.cavr-gcc–mmcu=atmega8–cdemo.c 这样就生成了所需目标文件disy.o、uart.o和demo.o,之后将这些目标文件连接到avr-avr- C基础不太好的读者便于理解,实际的项目中我们会使用Makefile,在Mfile生成的makefile中只要把要编译的源文件都列到SRC变量后便可生成静态连要构造一个静源文件按正常的编译方式生成目标(.oavr-ar将这些目标文件组合到一起,静态连接库名习惯是以“lib”开头,以“.a”为扩展名,avr-lib1.cMega8PB1口连接的发光管闪烁一次的FlashLedRed。静态库源程序硬件:CA-M8#include<avr/io.h>#include<avr/delay.h>#defineCLR_RED_LEDPORTB|=_BV(PB1)void{}Mega8PB0口连接的发光管闪烁一次。#include<avr/io.h>#include<avr/delay.h>#defineCLR_YEL_LEDPORTB|=_BV(PB0)void{}FlashLedRedFlashLedYel两个函数实现两个发光管不断的闪烁,文件main.c的内容如下:功能:静态库测试程序硬件:CA-M8(ChipArt-编译时钟:外部#include<avr/io.h>#include<avr/delay.h>#defineucharunsigned#define#defineuintunsignedvoidvoidDelayMs(uint{uinti;_delay_loop_2(4*}int{//I/O初始化{}} avr-aravr-ar-rmylib.alib1.oavr-gccavr-gcc-mmcu=atmega8main.cmylib.a-omain.cmylib.amain.elf,再用工具avr-objcopyavr-objcopy-Oihex-R.eeprommain.elf如果使用makefile编译main.c在Mfile生成的makefile中找到OBJ变量并将mylib.alib1.clib2.cDelayMs,这只是为了说明原理,说明象mylib.a这样的库,我会写一个如下的头文件与mylib.a一起发布。/*/* void用户会在程序中包含这个头文件并,调用库函 FlashLedRed、FlashLedYel第四章中断服务avr-gcc为中断提供缺省的例程,这些例程的名字已固定,用户可通过重写这些例例程将程序引导到0地址处(既复位。Avr-gcc为重写中断例程提供两个宏来解决细节的问题,它们是SIGNAL(signame)和INTERRUP(signame。参signame为中断名称,它的定io.h中包4-1列出ATMega8signame定义,其它器件的signame定义可查阅相应的ioxxxx.h文件。4-1ATMega8SPIUSARTUSARTUSARTTWI#include<avr/io.h>#include<avr/io.h>#include<avr/signal.h>{{}INTERRUPTSIGNALSIGNAL执行时全局中断触发位被voidsei(void)voidcli(void)定时器/计数器TCNT00包含计数值(0~255)TIFR(TimerInterruptFlagRegister)TOV0位为定时器/寄存器0溢出标志TIMSK:定时器中断寄存器(TimerInterruptMask硬件:CA-硬件:CA-2004-12-#include#define#defineucharunsigned#defineCLR_LEDint{ucharTCNT0=0;T/C0TCCR0=_BV(CS02)|_BV(CS00);ck/1024{ /1024/256/15≈1Hz{ } }}2004-12-#include<avr/io.h>#include<avr/signal.h>#defineucharunsigned#defineCLR_LEDstaticucharg_bCount=0;//中断计数器staticucharg_bDirection=0;{//产生中断周期T256*1024/T*151if(++g_bCount { //反向LED控制}}int{TCCR0=_BV(CS02)|_BV(CS00ck/1024TIMSK=_BV(TOIE0);//T/C0 看门狗 //Watchdog复位wdt_enable(timeout)//Watchdog使能 //Watchdogwdt.h,wdt.hWatchdog定时器超时符号常量,它们用于为wdt_enable函数提供timeout值。符号常量分别如下:符号常量 Watchdog定时器15毫秒超时 Watchdog定时器30毫秒超时 Watchdog定时器60毫秒超时 Watchdog定时器1秒超时 Watchdog定时器2秒超时Watchdog硬件CA-2004-12-#include<avr/io.h>#include<avr/wdt.h>#include<avr/delay.h>#defineucharunsignedchar#defineuintunsignedint#define#defineCLR_LEDvoidDelayMs(uint{uinti;_delay_loop_2(4}int{狗}UARTCA-M8S5-5(RXD)S5-6(TXD)MEGA8RXD、TXDCA-时钟:外部CA-时钟:外部2004-12-#include#defineucharunsignedchar#defineuintunsignedintvoidputc(uchar{while(!(UCSRA&(1<<UDRE)));}uchar{return} {//uartUBRRL=25;//9600baud6MHz:38 {}}2004-12-#include<avr/io.h>#include<avr/signal.h>#defineucharunsignedchar#defineuintunsignedintucharg_bTxdPos=0;//发送定位计数器ucharg_bTxdLen=0;//等待发送字节数ucharg_bRxdPos=0;//接收定位计数器ucharg_bRxdLen=0;//ucharg_aSendBuf[16]; uchar {ucharc=UDR;{}}SIGNAL{} {return}voidSendToUart(ucharsize){}{} main(void{uchar//uartUBRRL=25;//baud=9600 UBRR=CK/(baud*16)-1{ }} plete检测是否接收完成。4.5功能编 时钟2004-12-#include<avr/io.h>#include<avr/delay.h>#defineucharunsignedchar#defineuintunsignedint#defineFREQvoidDelayMs(uint{uint_delay_loop_2(FREQ*}intmain{ 输出引脚 {{}{}
if(- }return}模拟比S6-7#include<avr/io.h>#include<avr/signal.h>#defineucharunsigned//#defineCLR_RED_LED#defineSET_YEL_LEDPORTB&=0XFE//PB0#defineCLR_YEL_LED {if(ACSR&{}{}}int{//AIN0:AIN1:负极AIN0AIN1AC0=1if(ACSR&_BV(ACO)){}{}}A/D转换模块CA-M8R5S1-6,S1-5AREFMega8A/D转换测试程序编译2004-09-#include<avr/io.h>#include<avr/delay.h>#include<stdio.h>#defineucharunsigned#define unsignedstaticuint void{uchari;uintucharADCSRA=_BV(ADEN);//使能ADC,单次转换模式{}{{if(g_aAdValue[i]-{}}}{if(ret-{}}}{}return}int{uchar{}}Mega8A/D2004-09-#include<avr/io.h>#include<avr/signal.h>#include<avr/delay.h>#include<stdio.h>#defineucharunsignedchar#defineuint unsignedintvoidIoInit(void);{}int{uchar//使能ADC,中断允许,自由模式,时钟:ck/8{_delay_loop_2(4*250*}}ATMega8A/DADC按单次转换模式工作,每次转换均由置位ADSC触发。在中断方式示例中ADC按自由模式工作,自第一次置位ADSC起ADC就连续不断的进行采样转换、进行数据更新。)数码管显示程序CPU资源较多,相反、再描述。CA-M874hc595驱动,属于静态显示,这样的电路74hc595是个三态输出8位移位寄存器/锁存器,多个595可以串连使用,非常适合数码SCKSER上的电平信号被读入内部寄存器最低位。RCK是锁存S65、6、74-2gfedcba000111111100000110201011011301001111401100110501101101601111101700000111801111111901101111A01110111B01111100C00111001D01011110E01111001F01110001时钟2004-12-#include<avr/io.h>#include<avr/delay.h>#defineucharunsignedchar#defineuint unsignedint#define #defineSER_PORT #defineSER_DATPD4#defineSER_RCKPD5#defineSER_SCKucharg_aDis yBuf[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,\voidDelayMs(uint{uinti;_delay_loop_2(250*}//595voidser_out(uchar{uchar{}}//num:显示的数 voiddis y_number(ucharnum,ucharhex){uchartemp;if(hex)//十六进{ }else//{{ buf[0]|=0x80;//两个数码管小数点表示百位}}int{uchari=0; { }}键盘程序CA-M8S5-7和S5-8MEGA8PD2PD3S5-7S5-8PD2PD3设置成输出并置S3S4时数据的显示在十进制和十六时钟2004-12-#include<avr/io.h>#include<avr/delay.h>#defineucharunsignedchar#defineuint unsignedint#defineSER_PORT #defineSER_DAT #defineSER_RCK #defineSER_SCK #defineKEY1 voidDelayMs(uintvoid y_number(ucharnum,ucharuchar{{{{}}{{}}}returnret;}int{uchari=0,flag=0,key;PORTD=_BV(KEY0)|_BV(KEY1);//键盘引脚上拉电阻开 {{case0: disy_number(++i,flag);case1: disy_number(i,flag);}}}}时钟2004-12-#include<avr/io.h>#include<avr/delay.h>#include<avr/signal.h>#defineucharunsignedchar#defineuint unsignedint#defineSER_PORT #defineSER_DATPD4#defineSER_RCKPD5#defineSER_SCK#defineKEY1ucharg_aDis ucharvoidDelayMs(uintvoid y_number(ucharnum,uchar//外部中断0{ }int{PORTD=_BV(KEY0)|_BV(KEY1);//MCUCR=_BV(ISC00)|_BV(ISC01);//GICR=_BV(INT0);//0 // }蜂鸣器voidvoid{} 或avr-libc标准I/O流描avr-libc提供标准I/O流stdin,stdout和stderr。但受硬件资源的限制仅支持标准CFILE*FILE*fdevopen(int(*put)(char),int(*get)(void),intoptsattribute如果只指定put指针,流按写方式打开,stdout或stderr成为流的名。intput(charintput(char{⋯⋯return}回车,应当在put函数里发送‘\n’前发字符‘\r’。以下是一个基于UARTputintintuart_putchar(char{return}intint{⋯}get函数从设备一字节并按int类型返回,如果时发生了错误需返回–1intint FILE stream, constchar fmt, ap vfprintf将ap列出的值按fmt字符的形式输出到流stream。返回输出字节数,-Wl,-u,vfprintf-intint FILE stream, constchar fmt, ap vfscanf是libc提供的I/O流格式化输入函数的基础,在应用程序中很少直接调用。它从stream流按字符格式fmt内容后按转换规则将数据保存到参数列表ap内。与vfprintf类似vfscanf也支持三种不同模式。利用标准I/0流调试由于PC机串行口采用的是RS232标准,单片机与PC机串行口间的数据通信要有一个电平转换的接口电路,图5-1为采用公司的MAX202实现的接口电路,MAX202支持全双UART的电平转换,T1inT2inTTL/CMOS输入端,应接单TXDT1in和T2in的输入电平转换后分别从T1out和T2out输出,T1out和T2out应接PC串行口RXD引脚(DB9接器2。R1inR2inRS232输入端PC串行口TXD脚(DB9连接器3,信号通过电平转换后分别R1outR2out输出,R1outR2out片机RXD引脚。不在avr avr-libci/o硬件:CA-M8时钟:外部4MHz2004-11-#include#include<avr/pgmspace.h>#include<stdio.h>charintusart_putchar(char{return}int{returnUDR;}void{//UART初始化 //9600baud6MHz:384MHz:25//i/oUART}intmain(void){int{printf("1[输入一字符串]:\n");2:FLASH}}程序在IoInit例程中对UART接口初始化并使用fdevopen函数将I/O流连接到UART设备。printf/scanf的格式化字符串将占用RAM,大量的使用会耗尽有限的片内RAM。而printf_P/scanf_P是我们的选择,它的格式化字符串要求是在Flash内的数据,为此应PSTRPSTRpgmspace.h。号Windows为串行口的读写提供了缺省的驱动程序,在C(或C++)程序中可以使用WindowsAPICreateFile打开符“COMX(如 m是首选。号监测工具PrintMonitor就是一个使用 的VisualBasic源代码可到。PrintMonitor默认监测串行口1,将串行口接收到的数据按字符格式显示到上边的编辑框5-2PrintMonitor我并没有打包PrintMonitor,所以即使有它的可执行文件,如果系统中没有安装最小化的格式化打印avr-libc提供的流函数占用的FLASH空间较大,尽管最小连接都要占用1k多字节的程序器,所以AT90S2313等内部只有2K器的器件无法使用,为此我们可能需要写自己文件名:main.c硬件:CA-M8时钟:外部4MHz2004-11-#include#include #include //itoa函 #includevoidDelayMs(unsignedint{unsignedinti;_delay_loop_2(250*}intusart_putchar(char{return}voidminiprintf(char*fmt,{va_listap;char*p;intnval;unsignedchari;for(p=fmt;*p;p++){if(*p!={}switch{casenvalva_arg(ap,intitoa(nval,strval,10);case'x':nvalva_arg(ap,intitoa(nval,strval,16);}}intmain(void){unsignedinti=- //9600baud6MHz:384MHz:25{}}}miniprintf16度。va_listC语言参数列表类型,宏va_start用于指定第一个参数,va_arg负责从参调用va_end表示释放列表。5-3PrintMonitorWinAVR-编译FLASH序量598节。如果还嫌大,也可以进一步简化,那就是自己写itoa函数了,可以将转换十六进制格式功能去掉。第六章CA-M8上实现AT89S52编程ATMEL推出的89S系列单片机具AVRISP编程功能ISP接口为用户提供了一种对FLASH器串行编程方法ISP功能就象操作串行EEPROM器那样使单片机编程CA-M8ATMega8RS232I/OAT89S52ISPFLASH6-1 图6- PC上的程序利用一个通用的程序:LuckyProg2004,它有一个与很多编程软件那样的操作界面,它的编程操作就是按规定的协议将数据传送到指定的串行口,CA-M8上的单片机要做的就是接收到数据后写入到AT89S52,下一节将祥细介绍这个软件。图6-2为CA-M8与AT89S52引脚间的连线图,用ISP口程序时AT89S52必需XTAL0XTAL13~33MHz的晶振,ISP数据通信口MOSI、MISOSCK分别接ATMega8PC5、PC3PC4上I/OPC2通过一个三极管反向后连接到RST,主要是为了防止目标板上的复位电路使I/O口烧坏。图6- CA- 有仿真器的开发模式。2003年ATMEL推出了支持ISP功能的51单片机AT89S51和当时没有一个好的线能够或,双龙的软件SL-ISP号称配合它的并口的过分延时,这与PonyProg的CPU频率校准技术是不能比较的。最后我决定一个S52程序(LuckyProgS52)AT90S23132313I/O口操作习板(PDIUSBD12+AT89S52)就是使用它调试的,从可以关于但是在2004年下半年双龙又推荐一种新款ATMega48/88/168时我才发现,这样跟着ATMEL不休止的开发上位机程序是没有意义的。最终我有了一个构思,就是为这种模式的编程提供标准的上位机软件,于是之后的一个月内LuckyProg2004出现了。它不考虑给什么常是inhex实一WINDWS有了LuckyProg2004和类似CA-M8这样的硬件推出器件的编程不用再依赖少数的这些信息存诸到一个扩展名为“.lpc”的文件中,每一个器件必须有对应的LPC文件,⋯6-4所EEPROM被设置成1。下位机程序应根据接收的四字节写配置位。到LuckyProg2004的器件列表中,就可以使用了。当然,这时你必须要有下位机相应的程序支持真正的ISP编程操作,LuckyProg2004提供的仅仅是从计算机向下位机传送编程所需数据6-3LuckyProg20046-46-1LukcyProg2004 写FLASH读FLASH写EEPROM读EEPROMLP_READ_EEPROMLP_READ_FLASH:读FLASH器命令的流程如图6-6。LuckyProg2004将整个FLASH空间到缓冲区。:此命令流程如图LP_READ_FIRMWARE_MSG:此命令流程如图6-14所示。此命令从下位机24个字节数据,前8个字节认为是作者名(‘\0’,后16个字节是关于固件的其它信息(也是个需以‘\0’结尾的字符串。LuckyProg2004菜单“帮助”->“关于当前固件⋯”将执行此命令。6-5LP_WRITE_FLASH发发送器件ID(一字接收接收发发送操作命令CMD(共5个字节N操操作完6-6LP_READ_FLASH发发送器件ID(一字接收接收发发送操作命令CMD(共5个字节1:LP_READ_FLASH字节 接收接收N6-7LP_WRITE_EEPROM发发送器件ID(一字接收接收发发送操作命令CMD(共5个字节字节3:写入数据包个数高字节,字节4~5:0N操操作完6-8LP_READ_EEPROM发发送器件ID(一字接收接收发发送操作命令CMD(共5个字节1:LP_READ_EEPROM字节 数据包个数高字节,字节接收接收N6-9LP_ERASE_DEVICE发发送器件接收接收发发送5个字节数据,第一个字节为接收接收操操作完6-10LP_WRITE_BITS发发送器件ID(一字接收接收发发送操作命令CMD(共5个字节1:LP_WRITE_BITS2:LockByte字节3:FuseByte0字节4:FuseByte1字节5:FuseByte2接收接收操操作完6-11LP_READ_BITS发发送器件ID(一字接收接收发发送操作命令CMD(共5个字节格式:字节1:LP_READ_BITS字节2:0字节3:0字节4:0字节读读配置字节(共5个1:LP_READ_BITS2:LockByte字节3:FuseByte0字节4:FuseByte1字节5:FuseByte2操操作完6-12LP_SCAN_HARDWARE发送发送接收接收操操作完6-13LP_RESET_DEVICE发发送器件接收接收发送个5发送个5接收接收操操作完6-14LP_READ_FIRMWARE_MSG发送器件ID(发送器件ID(接收接收发送操作命令CMD(共5发送操作命令CMD(共5格式:字节1:LP_READ_FIRMWARE_MSG字节2:0字节3:0字节4:0字节格式:前8个字节为设计者名称,后16个字节为固件名称和版本(均字符格式以下是与LuckyProg2004对应下位机程序的框架,它假设硬件为CA-M8WINAVR编译。 :LuckyProg2004常量定义头文件 :uart通信功能函数定义头文件 :uart通信功能函数实现源文件 :#ifndefLP2004_H#define#define#define#define#define#define#define#define#define#define#define#define#define#ifndef#ifndefMY_USART_H#define#defineucharunsignedchar#defineuintunsignedint#define #defineUART_NO_WAIT #defineUART_NO_WAIT voidUar d(ucharlen);voiduchar功能:uart CPU编译速度:外部#include<avr/io.h>#include<avr/signal.h>#include"usart.h"#include"lp2004.h"staticucharvoidDelayMs(uintt);{ucharc=UDR;{}}{}
void d(uchar{}voidUartRecv(ucharlen,uchar{{}} {return}uchar{return}voidUartInit(void){uchar }LuckyProg2004下位机程序编程框架硬件:CA-M8(ChipArt-Mega8)编译时钟:外部#include<avr/io.h>#include<avr/delay.h>#include<avr/signal.h>#include<avr/interrupt.h>#include"usart.h"#include"lp2004.h"#defineFREQ4 #defineDEVICE_ID0X33 //器件ID#defineCLR_RED_LEDPORTB|=_BV(PB1)#defineCLR_YEL_LEDPORTB|=_BV(PB0) uchar //tvoidDelayMs(uint{uinti;_delay_loop_2(FREQ*}voidack(){ }ucharUartRecvEx(uintlen,uint{uintcount=0;{ return1;return0;}}void{uint {}}void{uinti; { }}void{uint {}}//LP_READ_EEPROM命令例void{uinti; { }}void{ }void{uchar*p;Uard(5);}void{}void{}//LP_READ_FIRMWARE_MSG命令void{uchar } {ucharuchar{ ID或回复器件检测命令{}else {}{}
{caseLP_READ_EEPROM casecaseLP_WRITE_BITS caseUsart.c文件里包含了UART通信函数,利用中断实现了数据接收的异步操作。全局变量g_aUartBuf是串行发送/接收数据在RAM内的缓冲区,它的大小等于数据包的长度LP_PACKET_SIZE。LP_PACKET_SIZELP2004.H中定义,应当根据需要修改这个值。如果要改成256及以上的数据,同时需要改变四个计数变量g_bTxdPos,g_bRxdPos,g_bTxdLen,g_bRxdLenunsignedchar类型,所以最大仅支持255字节的计数。缓冲区大小大于或等于256时应当将它们的数据类型改为unsignedint。AT89S52ISP功能简周期至少大于6个CPU时钟(XTAL1上的)周期。0X69,表示编程使能命令成功。不论响应正确与否,必需保证四字节的时钟周期。的编程模式,在5V编程电压下典型编程时间少于1ms。表6- ISP命 10100101xxxx01101001(1010100xxxxxxxxx0010xxxA12-A7-D7-0100xxxA12-A7-D7-10101110xxxxxxxx0010XXXXxxxxxxLB3LB2LB10010XXXA5-xxxx0011XXXA12-ByteByte1-0101XXXA12-ByteByte1-C程序里的延时模块为一个计数循环,延时时间的长短往往是先估计,后通过实验或仿真等方法来验证。avr-libcAPI函数,利用这两个函数我们voidvoid_delay_loop_1(unsignedcharvoidvoid_delay_loop_2(unsigned count4count16若要调用这两个函数,需先包函头文件delay.h,实际上这两个函数的实现就在此文件里,我们可以从WINAVR安装 里的\AVR\INCLUDE\AVR子 以下为_delay_loop_2的源程序:staticstaticinline_delay_loop_2(unsignedint{asmvolatile"1:sbiw%0,1""\n\t""brne1b":"=w"(:"0"(}(staticcount*4个时钟周期。要注意的是,inline关键字说明以下是为编程器主控单片机ATMega8写的延时程序,它以毫秒为单位执行延时任务。voidvoidDelayMs(unsignedint{unsignedinti;_delay_loop_2(FEQ*250-}的,在CA-M8实验板上测试通过。以下是添加支持AT89S52ISPmain.c代码:#defineSCKPC4#defineMISOPC3#defineMOSI#definePROGPORT #definePROGDDR #definePROGPIN #defineCLR_RED_LEDPORTB|=_BV(PB1)#defineCLR_YEL_LEDPORTB|=_BV(PB0)#defineSET_BEEPPORTB|=_BV(PB2)#defineCLR_BEEP mand[5];//constcharg_firmmsg[]PROGMEM="芯 //tvoidDelayMs(uint{uinti;_delay_loop_2(FREQ*}void{}voidBeep(uchar{uchari;{}}{uchari;{}}uchar{ucharret=0;uchari;{}returnuchar{//MOSI、SCK设为输出return1;}
return//S52void{//MOSI、SCK设为输入高阻}voidack(void){ }ucharUartRecvEx(uintlen,uint{uintcount=0;{ return1;return0;}}void{uinti; uchar*p=UartGetBuffer();{return;}{ISP_WriteByte((uchar)(i/2));//Writeaddress{}{}}}void{uinti; {return;}{ }}void{uint {}}//LP_READ_EEPROM命令例void{uinti; { }}void{uchar{return;}}void{ucharc,*p;{return;}elseelse }void{return;}void{}//LP_READ_FIRMWARE_MSG命令void{uchar } {ucharuchar{ ID或回复器件检测命令{}else{}{}
{caseLP_READ_EEPROM caseLP_WRITE_BITS caseDEVICE_ID的值是可任意设置的,只要与LuckyProg2004中设置的器件ID相匹配便可,这里我设置成了0x69。LuckyProg2004的器件列表当中。6-15AT89S52到此我们已经实现了一个非常实用的AT89S52编程器,一个人的精力的确有限,真心希望LuckyProg2004和CA-M8能够得到广大单片机者的大力支持,将来能实现器件的请关注或,我将在这里列第七章TWITWI模块概ATMega系列单片机片内集成两线制串行接口模块,Atmel文档称它为TWI接口。事实上TWI与PHILIPS的I2C总线是同一回事,之所以叫它TWI是因为这样名可使Atmel避免交术语版税。所以,TWI兼容I2C更一种说法。AVR硬件实现的TWI接口是面向字节和基于中断的,相对软件模拟I2C总线有更好的实时能,在TWI使能时可设置SCL和SDA引脚对应的I/O口内部上拉电阻有效,这样可省去I2C不论主控模式还是被控模式都应TWITWCR的TWEN位置1TWI模块。TWEN位被置位后I/OPC5PC4被转SCL和SDA,该管脚上的斜率限制和毛刺(答允许)1,TWI模块就可以对总线上对它的寻址做出应答,并置状态字。的操作。关于不同模式下的状态值的详细描述参考MEGA8的。主控模式操作实时时钟表7- 010010010000000000010100000--56节时自动加一,当指针越过DS1307RAM尾部时指针将返回到0地址处。方波信号输出功能从SQW/OUT引脚输出设置频率的方波,CONTROL寄存器用于控BIT7(OUT(输出)时若OUT为1则SQL/OUT脚为高电平,反之亦然BIT4(SQWE)方波输出允许/控制位,1有效。(RS0表7- 输出频率001011 二DS1307Vbat引脚接的电池电压必需在2.0V~3.5V范围内。当VCC引脚上的电压降到1.25倍电池电压时DS1307内部写保护电路生效,RTC数据和内部RAM的读写补。图6- 三时钟:外部2004-09-#include<avr/io.h>#include<avr/delay.h>#include<avr/twi.h>#include<avr/pgmspace.h>#include<stdio.h>#defineuintunsignedint#defineucharunsigned#defineFREQ#defineDS1307_ADDR#defineTW_ACK#defineTW_NACK#defineRTC_READ#defineRTC_WRITEFILEucharg_aTimeBuf[7BCDvoidDelayMs(uint{uinti;_delay_loop_2(FREQ}intusart_putchar(char{return}int{returnUDR;}void{ //9600baud6MHz:384MHz:25//UARTI/O}voidtwi_stop(void){TWCR=_BV(TWINT)|_BV(TWSTO)|}uchar{TWCR=_BV(TWINT)|_BV(TWSTA)|_BV(TWEN);while((TWCR&_BV(TWINT))==0);return}uchartwi_writebyte(uchar{TWDR=TWCR=_BV(TWINT)|_BV(TWEN);while((TWCR&_BV(TWINT))==0);return}uchartwi_readbyte(uchar*c,ucharack){ucharwhile((TWCR&_BV(TWINT))==0)return}ucharrtc_write(ucharaddr,uchar*buf,uchar{uchartwi_writebyte(addr);//writeaddressreturn}ucharrtc_read(ucharaddr,uchar*buf,uchar{uchari;rtc_write(addr,0,0);//setaddressreturn0;}void{} ucharRtcUpdateData(uchar{ucharret; return}ucharRtcReadRAM(ucharaddr,
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 骨科患者营养状况评估
- 辽宁省沈阳市铁西区达标名校2026届初三5月月考(物理试题理)试题含解析
- 河南省林州市第七中学2025-2026学年初三4月质量检测试题物理试题含解析
- 河南省2025-2026学年初三押题信息卷物理试题(三)含解析
- 广东省高州市谢鸡镇达标名校2026届初三第一次调研考试数学试题含解析
- 骨科手术前后护理
- 湖北省黄石市阳新一中卓越联盟2026年中考物理试题命题比赛模拟试卷(27)含解析
- 腹泻时小儿的心理护理
- 老年骨质疏松症患者的运动康复
- 智研咨询发布-2026年中国颈椎病用药行业现状、发展环境及投资前景分析报告
- 新东方《中国学生出国留学发展报告》
- 2026年3月15日九江市五类人员面试真题及答案解析
- 文化旅游嘉年华主题活动方案
- 投资促进局内部控制制度
- 2026年常州机电职业技术学院单招职业倾向性测试题库附答案详解(a卷)
- 2026教育培训产业市场供需分析与未来发展预测研究报告
- 2026春统编版六年级道德与法治下册(全册)课时练习及答案(附目录)
- 2026年安庆医药高等专科学校单招综合素质考试题库及答案1套
- 2026年《必背60题》抖音本地生活BD经理高频面试题包含详细解答
- 2025天津市西青经开区投资促进有限公司面向全国公开招聘招商管理人员4人备考笔试试题及答案解析
- 鼻饲喂养的技巧与技巧
评论
0/150
提交评论