找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3181|回复: 0
打印 上一主题 下一主题
收起左侧

PXA270处理器ADS编程 嵌入式实验报告

[复制链接]
跳转到指定楼层
楼主
ID:108615 发表于 2016-3-14 16:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
实验目的
①了解PXA270处理器结构
②了解ARM指令集
③了解嵌入式系统的引导过程
④了解八段数码管的知识
⑤了解系统的硬件寻址方式
⑥掌握ADS编程和调试方法
⑦掌握JTAG调试技巧

实验内容
①分析PXA270基本结构
②分析Eeliod实验平台实现的存储系统架构
③分析PXA270的引导过程
④分析Eeliod实验平台LED发光管和7段数码管的设计原理图
⑤参考系统引导示例程序完成数码管的控制代码
⑥编译程序,下载执行,让数码管显示一组特定的数组

实验原理
①LED实验原理
实验板上的八个LED的阴极直接与锁存器74574的输出端相连,阳极通过限流电阻上拉到+5V,所以锁存器的输出直接控制了LED的发光与否;锁存器的输入连接到PXA270的数据总线的低八位上,锁存器的锁存信号来自一块3-8译码器的输出Y5,所以Y5从低到高的跳变将PXA270数据总线第八位数据送到锁存器锁存住,而3-8译码器的输入的译码信号ABC连接到PXA270地址线的A20、A21和A22上,所以Y5选中需要A22~A20为101b;另外3-8译码器的使能控制信号G2B与PXA270的内存空间片选信号CS4相连,CS4片选的内存地址空间为0x1000_0000~0x13FF_FFFF,为简单起见,可将设为0x1000_0000,再加上A22~A20的编码可得到LED的片选地址为0x1000_0000+0x0050_0000=0x1050_0000,后面只需向该地址写一个字节的数据就可以控制LED。
②数码管实验原理
实验板上有四个一位共阳极八段数码管,采用分立的锁存器单独控制。数码管的阴极通过限流电阻直接与锁存器74574的输出相连。数码管的第八段小数点没有使用,相应的第八段控制信号被用来控制数码管的通电与否,通过一个PNP的三极管来控制,锁存器输出的Q8脚连接到该三极管的基极,Q8低电平时三极管导通,数码管供电,所以数码管正常显示时Q8必须为低电平。以上对于四个数码管通用。对于第一二个数码管,它们相连的锁存器的输入数据信号分别为PXA270数据信号的D0~D7和D8~D15,两个锁存器的片选信号都接到LED实验原理中提到的3-8译码器的Y3上,同LED实验原理中的地址计算方法,可得数码管1和2的地址为0x1000_0000+0x0030_0000=0x1030_0000,后面控制数码管1和2时只需要向这个地址写半个字(16位)的数据即可,其中数据的低八位对应第一个数码管,高八位对应第二个数码管(注意需要将每个八位的最高位置0来打开数码管的供电)。数码管3和4的控制跟1和2的控制类似,只不过将地址改为0x1000_0000+0x0040_0000=0x1040_0000即可。

实验步骤
第一步 分析代码
结合以上说明,对本实验提供的示例代码分析,深入理解针对具体的硬件实现,软件是如何配合工作的。
第二步 程序的编译和下载
利用ADS打开示例工程文件,执行Project→Make,编译、链接生成可执行映像文件
第三步 观察系统运行情况,对系统进行源码调试

程序说明
①LED控制
通过对LED的地址直接写入数据即可完成对LED的控制,在高级语言中一般无法直接完成对内存指定地址的操作,但在C语言中可以利用指针来完成该操作。同时由于PXA270内部带有高速缓存Cache,所以需要用关键字volatile来限定该指针使得每次对指针的操作都直接操作到内存,而不通过Cache。
②数码管控制
数码管基本控制原理与LED控制相同,只是地址换成数码管的地址。实验板上共有4个数码管,4个数码管分成两组,每组用一个地址;在一组内,用16位二进制(半字)来控制两个数码管;注意要使数码管正常工作,每个该半字的第8位和第16位必须为0来控制三极管打开使得数码管通电。

程序源代码、注释
①LED代码
  1. //LED地址
  2. #define LED_VALUE                (*((volatile unsigned char *)(0x10500000)))

  3. //位定义
  4. #define BITNULL        (0x00<<0)
  5. #define BIT0                (0x01<<0)
  6. #define BIT1                (0x01<<1)
  7. #define BIT2                 (0x01<<2)
  8. #define BIT3                (0x01<<3)
  9. #define BIT4                (0x01<<4)
  10. #define BIT5                (0x01<<5)
  11. #define BIT6                (0x01<<6)
  12. #define BIT7                (0x01<<7)

  13. //粗略延时函数
  14. void Delay(unsigned int x)
  15. {
  16.         unsigned int n, j, k;
  17.         for (n =0; n <=x; n++)
  18.                 for (j = 0; j <0xff; j++)
  19.                         for (k = 0; k <0xff; k++);
  20. }

  21. int main(void)
  22. {       
  23.         int i;
  24.         //流水花样查找表,这里是逻辑层0表示不显示,1表示显示,与硬件无关
  25.         unsigned char LUT[] =
  26.         {
  27.                 BIT0 + BIT7,
  28.                 BIT1 + BIT6,
  29.                 BIT2 + BIT5,
  30.                 BIT3 + BIT4,
  31.                 BIT2 + BIT5,
  32.                 BIT1 + BIT6,
  33.                 BIT0 + BIT7,
  34.                 BITNULL,
  35.         };

  36.         while (1)
  37.         {       
  38.                 LED_VALUE = 0xff;
  39.                
  40.                 for (i = 0; i < 8; i++)
  41.                 {
  42. //这里是电气层,由于LED是共阳极,所以这里需要取反
  43.                         LED_VALUE = ~LUT[i];
  44. Delay(200);
  45.                 }
  46.         }
  47.        
  48.         return 0;
  49. }

  50. ②数码管代码
  51. 1)SegLed.h文件
  52. #ifndef __SEGLED_H__
  53. #define __SEGLED_H__

  54. #define SEG_NULL        ('9' + 1)

  55. //显示数字函数的控制参数
  56. enum
  57. {
  58.         DISP_NORMAL = 0,
  59.         DISP_BLANKING
  60. };

  61. extern signed char SegLedDispAt(unsigned char, signed char);
  62. extern signed char SegLedDispNum(short, unsigned char);

  63. #endif

  64. 2)SegLed.c文件
  65. #include "SegLed.h"

  66. //第一组和第二组数码管的地址
  67. #define SEGLED0                (*((volatile unsigned short int *)(0x10300000)))
  68. #define SEGLED1                (*((volatile unsigned short int *)(0x10400000)))

  69. //数码管上各个段对应一个字节中的某个位的宏定义
  70. #define        SEGA        (0x01<<0u)
  71. #define        SEGB        (0x01<<1u)
  72. #define        SEGC        (0x01<<2u)
  73. #define        SEGD        (0x01<<3u)
  74. #define        SEGE        (0x01<<4u)
  75. #define        SEGF        (0x01<<5u)
  76. #define        SEGG        (0x01<<6u)
  77. #define        SEGH        (0x01<<7u)

  78. //数码管显示不显示以及显示0~9宏定义,这里只是逻辑层的定义,具体还需根据数码管是共的什么极来确定需不需要取反
  79. #define DIGNULL        (SEGH)
  80. #define DIG0                (SEGA + SEGB + SEGC + SEGD + SEGE + SEGF + SEGH)
  81. #define DIG1                (SEGB + SEGC + SEGH)
  82. #define DIG2                (SEGA + SEGB + SEGD + SEGE + SEGG + SEGH)
  83. #define DIG3                (SEGA + SEGB + SEGC + SEGD + SEGG + SEGH)
  84. #define DIG4                (SEGB + SEGC + SEGF + SEGG + SEGH)
  85. #define DIG5                (SEGA + SEGC + SEGD + SEGF + SEGG + SEGH)
  86. #define DIG6                (SEGA + SEGC + SEGD + SEGE + SEGF + SEGG + SEGH)
  87. #define DIG7                (SEGA + SEGB + SEGC + SEGH)
  88. #define DIG8                (SEGA + SEGB + SEGC + SEGD + SEGE + SEGF + SEGG + SEGH)
  89. #define DIG9                (SEGA + SEGB + SEGC + SEGD + SEGF + SEGG + SEGH)


  90. unsigned short segBuff0, segBuff1;        //定义数码管的"显示缓冲"


  91. /*
  92.         名    称:SegLedDispAt()
  93.         功    能:在四个数码管的指定位置显示指定的字符
  94.         入口参数:ch:需要显示的字符的ASCII值,目前支持的字符仅限于数字0~9(即'0' <= ch <= '9')和空字符SEGNULL
  95.                           pos:显示的字符位于哪个数码管,0 <= pos <= 3 分别表示第一到第四个数码管
  96.         出口参数:正确执行返回0,否则返回-1
  97.         说    明:本函数是对于底层数码管的硬件抽象,所有上层驱动都调用此函数完成各种显示功能,一般情况下用户程序
  98.                           不需要调用此函数。确实需要调用此函数时,注意第一个参数是ASCII值,不是数字,而是数字对应的ASCII
  99.         使用范例:SegLedDispAt('6', 0); 在第一个数码管上显示数字6
  100. */
  101. signed char SegLedDispAt(unsigned char ch, signed char pos)
  102. {
  103.         unsigned char tempDisp;
  104.         const unsigned char segLUT[] = {DIG0, DIG1, DIG2, DIG3, DIG4, DIG5, DIG6, DIG7, DIG8, DIG9, DIGNULL};
  105.         if((pos < 0) || (pos > 3))
  106.                 return -1;
  107.        
  108.         tempDisp = ~segLUT[ch - '0'];        //数码管共阳极的需要在这里取反,注意共阴极的除了不需要取反还要修改空显示的宏定义
  109.                
  110.         switch(pos)
  111.         {
  112.                 case 0: segBuff0 = ((segBuff0 & 0xFF00) | tempDisp);break;
  113.                 case 1: segBuff0 = ((segBuff0 & 0x00FF) | tempDisp << 8);break;
  114.                 case 2: segBuff1 = ((segBuff1 & 0xFF00) | tempDisp);break;
  115.                 case 3: segBuff1 = ((segBuff1 & 0x00FF) | tempDisp << 8);break;
  116.                 default:break;
  117.         }
  118.        
  119.         SEGLED0 = segBuff0;
  120.         SEGLED1 = segBuff1;
  121.        
  122.         return 0;
  123. }

  124. /*
  125.         名    称:SegLedDispNum()
  126.         功    能:在四个数码管上显示0~4位正整数
  127.         入口参数:num:需要显示的正整数,范围0~9999
  128.                           argv:显示控制参数,目前可选赋值为DISP_NORMAL和DISP_BLANKING支持普通显示(不够四位时前面补零)
  129.                           和消隐显示(不够四位时右对齐,前面不足处不显示)
  130.         出口参数:正确执行返回0,否则返回-1
  131.         说    明:无
  132.         使用范例:SegLedDispNum(666, DISP_BLANKING); 在数码管上显示666,右对齐,第一个数码管不显示
  133. */
  134. signed char SegLedDispNum(short num, unsigned char argv)
  135. {
  136.         unsigned char numLen = 0;
  137.         signed char i;
  138.         short tempNum;
  139.        
  140.        
  141.         if(num < 0 || num > 9999)
  142.                 return -1;
  143.        
  144.         switch(argv)
  145.         {
  146.                 case DISP_NORMAL:
  147.                 {
  148.                         for(i = 3; i != -1; i--)
  149.                         {
  150.                                 SegLedDispAt(num % 10 + '0', i);
  151.                                 num /= 10;
  152.                         }
  153.                         break;
  154.                 }
  155.                
  156.                 case DISP_BLANKING:
  157.                 {
  158.                         numLen = 1;
  159.                         for(tempNum = num; tempNum /= 10; numLen++);        //计算数字长度,供消隐使用
  160.                        
  161.                         for(i = 3; i != 3 - numLen; i--)
  162.                         {
  163.                                 SegLedDispAt(num % 10 + '0', i);        //从个位开始一直显示到消隐前一位
  164.                                 num /= 10;
  165.                         }
  166.                        
  167.                         for(; i != -1; i--)
  168.                         {
  169.                                 SegLedDispAt(SEG_NULL, i);        //对剩下的前面几位消隐(写空)
  170.                         }
  171.                         break;
  172.                 }
  173.                 default:
  174.                         break;
  175.         }
  176.        
  177.         return 0;
  178. }
复制代码


总结
ADS集成开发环境的编译器不支持在函数外对全局变量进行初始化,在LED实验时,定义了一个全局的查找表,通过查找表控制LED的显示花样,但是在运行时发现LED的显示始终不对,后来在单步调试的时候发现全局变量那个查找表的内容根本不对,后来在函数内部定义了一个查找表,问题解决。


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表