[PIC®/AVR®/dsPIC®产品] AVR 8位单片机汇编——GPIO操作

[复制链接]
1480|9
 楼主| JackTang1994 发表于 2022-1-7 11:14 | 显示全部楼层 |阅读模式
本帖最后由 JackTang1994 于 2022-1-13 09:43 编辑

#技术资源# #申请原创#

要求:最好有学习过C语言

AVR汇编器使用文档:https://ww1.microchip.com/downloads/en/DeviceDoc/40001917A.pdf
AVRASM2汇编器下载:http://www.vfx.hu/avr/download/avrasm2.zip
AVR指令集文档:https://www.microchip.com/DS40002198
ATmega4809 Curiosity Nano开发板:https://ww1.microchip.com/downloads/en/DeviceDoc/ATmega4809_Curiosity_Nano_Schematics.pdf

软件环境:MPLAB X IDE v5.5,AVRSAM2汇编器
硬件环境:ATmega4809 Curiosity Nano开发板

汇编文件组成
伪指令:操作汇编器的指令,不会被编译到代码中
代码指令:操作MCU的指令,真正执行的代码。
注释:注释符号有";",有些汇编器支持"//"和"/**/"
符号标签:用于标识地址,类似于C语言中的函数名
以下代码为一个完整的汇编示例,包含上述所列的部分
  1. .include <m4809def.inc>

  2. Start_main:   
  3.    
  4.     ldi r23, 0x20 ; Toogle PF5
  5.     out PORTF_OUTTGL, r23

  6.     rjmp Start_main  

什么是伪指令?
答:伪指令,其实不是汇编指令编译后不会被编译成代码。它是用来指导汇编器进行汇编操作的,不同的汇编器使用的伪指令不一样。
什么是指令?
答:指令就是实实在在的代码程序,用于操作处理器(MCU)的。

汇编指令类型
数据传输(内存操作):数据读取,外设操作
程序流程操作(跳转指令):函数调用、跳转等
逻辑、算术运算:+、-、*、/和与、或、非、异或等运算
位操作:左移、右移等操作MCU操作指令:BREAK、NOP等
具体的指令说明需要查看AVR指令集文档

汇编文件格式
*.asm、*.s、*.S、*.850、*.v800等

汇编与C语言区别?
答:汇编代码执行速度快和具体芯片内核有关,不同的芯片内核所使用的汇编指令不同。汇编代码运行环境简单,占用空间少,移植性差。
C语言移植性好与具体的芯片内核无关,易于阅读,占用空间比汇编大些,C语言运行需要相关环境(最简单需要栈空间,复杂的需要堆以及库函数等).汇编语言对硬件的操作性是最灵活的可以任意操作硬件。汇编语言一般用于MCU底层的开发如:启动代码、操作系统底层实现等。C语言可移植性好,一般用于外设驱动的开发如:串口、SPI、网口、USB等驱动。

先不讲AVR的指令集,而是通过一个具体的实例来解释。这样应该更容易让人接受,好的接下来就开始写代码。  
程序的主流程很简单:每隔0.5秒翻转一次LED引脚的电平。


程序比较完整的流程图:延时0.5秒的代码分成了两层循环,因为一层循环延时时间不够。



C语言实现
  1. #include <iom4809.h>

  2. int main(void)
  3. {
  4.     uint16_t i = 1000;
  5.     uint8_t j = 100;

  6.     PORTF_DIR = 0x20;

  7.     while(1)
  8.     {
  9.         PORTF_OUTTGL = 0x20;
  10.         j = 100;
  11.         while(j--)
  12.         {
  13.             i = 1000;
  14.             while(i--);
  15.         }
  16.     }  
  17. }

将C语言转换成汇编实现
从上面C语言代码中,我们可以得到"循环"、”条件判断“、”变量名定义“等部分,而汇编与之对应的指令分别如下:


循环:使用跳转指令和标签
条件判断:使用带条件跳转指令、状态寄存器、标签
变量名定义:使用.def汇编伪指令、普通寄存器
具体代码实现如下:
  1.     ; code by jack
  2.     .include <m4809def.inc>        ; 包含ATmega4809头文件。头文件路径可以从我上一篇**了解,可以使用文本编辑工具打开它查看里面的内容。
  3.    
  4.     ; default system clock : 20/6 = 3.333MHZ ATmega4809芯片默认的时钟为内部20MHZ,默认分频系数为6
  5.    
  6.     ; .def汇编器伪指令。此处用于定义寄存器的别名,后续可以再次用.def修改其名称。
  7.     .def mask = r16
  8.     .def ledR = r17


  9.     .def outLoopR = r18            ; 外层循环数值的数值保存寄存器
  10.     .def innLoopRL = r24    ; 内层循环数值的数值高8位数保存寄存器
  11.     .def innLoopRH = r25    ; 内层循环数值的数值低8位数保存寄存器
  12.    
  13.     ; .equ汇编器伪指令。定义常量,后续不可以再修改类似C语言的const。
  14.     .equ oVal = 208     ; 外层循环数值
  15.     .equ iVal = 1999    ; 内层循环数值
  16.    
  17.    
  18.     ; .CSEG汇编器伪指令。表示将以下代码放置在代码段。
  19.     .CSEG
  20.     .ORG 0x00 ; code space开始地址。这个地址可以从芯片手册的Memory章节获取。后续会解释下
  21.    
  22.     ; 初始化LED使用的IO引脚
  23.     ; PF5
  24.     ; output mode
  25.     ldi r23, 0x20   ; 将0x20加载到r23寄存器。PF5对应第PortF控制寄存器中的第6位
  26.     sts PORTF_DIR, r23        ; 设置为输出模式
  27.    
  28. Start_main:    ; 符号标签,可以自定名称。这个相当于C语言中的函数名称。它可以表示地址
  29.     ; Toogle PF5。翻转LED相应的IO引脚电平
  30.     ldi r23, 0x20   ; 1 cycle。将0x20数据加载到r23寄存器中
  31.     sts PORTF_OUTTGL, r23   ; 2 cycle。将r23寄存器中为数值写入到Data space空间

  32.     ldi outLoopR, oVal        ; 1 cycle。将oVal数据(208)加载到r23寄存器中
  33. Delay_ms: ; 符号标签,可以自定名称。这个相当于C语言中的函数名称。它可以表示地址
  34.     ; delay 500ms
  35.     ldi innLoopRL, LOW(iVal) ; 1 cycle。 LOW为汇编器内置的函数,只取iVal的低8位数据
  36.     ldi innLoopRH, HIGH(iVal) ; 1 cycle  HIGH为汇编器内置的函数,只取iVal的高8位数据
  37.     ; delay ms

  38. delay_us: ; 符号标签,可以自定名称。这个相当于C语言中的函数名称。它可以表示地址
  39.     ; 2 cycle
  40.     ; sbiw指令为字操作指令,它能操作两个连续的寄存器且会自动操作Carry位。简单讲就是可以操作16bit的数据,只需要给它低的寄存器
  41.     ; 因为iVal为16位的数据,上面代码已经将它的低8位和高8位分别保存到了r24,r25寄存器中了。所以这里只需要给r24寄存器。sbiw指令会
  42.     ; 处理完低8位的数据后自动将r25寄存器中的数据进行减1运算。
  43.     sbiw innLoopRL, 1 ; sbiw减法运算。这里表示减1
  44.     brne delay_us ; 1 or 2 cycle。条件跳转,判断上一条指令sbiw innLoopRL, 1结果是否不等0
  45.    
  46.     dec outLoopR ; 1 cycle。 自减1。相当于C语言中i--操作
  47.     brne Delay_ms ; 1 or 2 cycle。条件跳转,判断上一条指令dec outLoopR, 1结果是否不等0
  48.    
  49.     rjmp Start_main    ; 2 cycle。跳转到Start_main标签符号处
关于.ORG伪指令后为什么是0x00地址?
从数据手册的Memory章节可以的Memory map图中可以看出,在Code Space中Flash的开始地址为0x0000

个人理解:关于Code Space与Data Space的区别主要是使用指令的不同,有些指令只能操作Flash。而ATmega4809将Flash区域映射到了Data Space所以可以使用Data Space的指令来操作Flash.
关于汇编器内置的函数有哪些?
这个可以从AVR汇编使用手册中第7章节可以查询到。比如:上述代码中使用到的LOW()、HIGH()函数



实际效果:





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
tpgf 发表于 2022-2-3 16:02 | 显示全部楼层
汇编器都是内置的吗
keaibukelian 发表于 2022-2-3 16:13 | 显示全部楼层
这个伪指令的作用是什么呢
labasi 发表于 2022-2-3 16:23 | 显示全部楼层
现在用的是不是比较少了啊
paotangsan 发表于 2022-2-3 16:31 | 显示全部楼层
首先我读不懂汇编语言啊
renzheshengui 发表于 2022-2-3 16:39 | 显示全部楼层
几个要素都很全面
wakayi 发表于 2022-2-3 16:47 | 显示全部楼层
有专用的转换器吗
 楼主| JackTang1994 发表于 2022-2-8 10:38 | 显示全部楼层
tpgf 发表于 2022-2-3 16:02
汇编器都是内置的吗

单独下载或者从MicroChip Studio安装目录中获取,MPLAB X IDE中没有带这个AVR汇编器
 楼主| JackTang1994 发表于 2022-2-8 10:38 | 显示全部楼层
paotangsan 发表于 2022-2-3 16:31
首先我读不懂汇编语言啊

看看就清楚了,不需要记住每一个指令。不同就查汇编指令文档即可
 楼主| JackTang1994 发表于 2022-2-8 10:39 | 显示全部楼层
keaibukelian 发表于 2022-2-3 16:13
这个伪指令的作用是什么呢

指导汇编器的,伪指令不会产生代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则

29

主题

64

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部