单片机上机实验报告

实验一 数码管实验

一.实验目的

1.了解数码管的显示原理;

2.掌握JXARM9-2440 中数码管显示编程方法。

二.实验原理

7段LED由7个发光二极管按“日”字形排列,所有发光二极管的阳极连在一起称共阳极接法,阴极连在一起称为共阴极接法。

LED显示器的接口一般有静态显示与动态显示接口两种方式。本实验中采用的是动态显示接口,其中数码管扫描控制地址为0x20007000,位0-位5每位分别对应一个数码管,将其中某位清0 来选择相应的数码管,地址0x20006000 为数码管的数据寄存器。数码管采用共阳方式,向该地址写一个数据就可以控制LED 的显示,其原理图如图所示。

三.实验内容及步骤

1、六个数码管同时正向显示0-F ,然后反向显示F-0。

1) 参照模板工程leddemo(modules\leddemo\leddemo.apj),添加相应的文件,并修改led 的工程设置;

2) 创建led.c 并加入到工程led 中;

3) 编写LED 显示函数void led_display(void),正向显示0-F 然后反向显示F-0,并循环执行以上动作,在每次显示之间延时一段时间;

4) 编译led,成功后,下载并运行,观察结果。

2、在六个数码管上依次显示“HELLO”,可分辨出轮流显示。步骤同上。

3、在六个数码管上依次显示“HELLO”,分辨不出轮流显示。步骤同上。

4、在每个数码管上递增显示0-9 。步骤同上。

四.实验程序

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

/*文件名称: LEDSEG7.C                                                      */

/*实验现象: 数码管依次显示出0、1,2、……9、A、B、C、D、E、F               */

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

#define U8 unsigned char

unsigned char seg7table[18] = {

    /* 0       1       2       3       4       5       6      7*/

    0xc0,   0xf9,   0xa4,   0xb0,   0x99,   0x92,   0x82,   0xf8,

    /* 8       9      A        B       C       D       E      F*/

    0x80,   0x90,   0x88,   0x83,   0xc6,   0xa1,   0x86,   0x8e,

    /*H      L   */

    0x89,   0xc7,  

};

void Delay(int time);

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

/* 函数说明: JXARM9-2410 7段构共阳数码管测试                               */

/* 功能描述: 依次在7段数码管上显示0123456789ABCDEF                         */

/* 返回代码:                                                              */

/* 参数说明:                                                              */

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

void Test1_Seg7(void)          //正向和反向显示

{   

       int i;     

       *((U8*)0x20007000)=0x0;

       for( ; ; )

       {

       for(i=0;i<0x10;i++)

       {

              *((U8*)0x20006000)=seg7table[i];

              Delay(9000); 

       }

       for(i=0xf;i>=0;i--)

       {

              *((U8*)0x20006000)=seg7table[i];

              Delay(9000);

       }

       }

}

void Test2_Seg7(void)               //显示hello,更改Delay的数值,可得分辨出和分辨不出

{   

       int i;     

       for( ; ; )

       {

              *((U8*)0x20007000)=0x3e;

              *((U8*)0x20006000)=seg7table[0];

              Delay(1);

             

              *((U8*)0x20007000)=0x3d;

              *((U8*)0x20006000)=seg7table[17];

              Delay(1);

             

              *((U8*)0x20007000)=0x3b;

              *((U8*)0x20006000)=seg7table[17];

              Delay(1);

             

              *((U8*)0x20007000)=0x37;

              *((U8*)0x20006000)=seg7table[14];

              Delay(1);

             

              *((U8*)0x20007000)=0x2f;

              *((U8*)0x20006000)=seg7table[16];

              Delay(1);

       }

}

unsigned char table[6]={0x3e,0x3d,0x3b,0x37,0x2f,0x1f};            //递增显示0~9

void Test3_Seg7(void)

{   

       int i,j;   

       for(;;)

       {

              for(j=0;j<6;j++)

              {

              *((U8*)0x20007000)=table[j];

              for(i=0;i<0xa;i++)

              {

                     *((U8*)0x20006000)=seg7table[i];

                     Delay(10000);      

              }

              }

             

       }

}

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

/* Function name : 循环延时子程序                                           */

/* Description : 循环 'time'                                              */

/* Return type void                                                       */

/* Argument      : 循环延时计数器                                           */

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

void Delay(int time) {

    int i;

       int delayLoopCount=1;

    for(;time>0;time--);

              for(i=0;i<delayLoopCount;i++);

}

五.结果及分析

1.六个数码管同时显示,从0——F,接着从F——0反向显示。

通过地址20007000选择哪个数码管亮,通过地址20006000决定数码管输出的内容。再通过循环可完成轮流显示。

2.可分辨出:从数码管的右边至左边依次显示hello

   分辨不出:数码管上显示hello。

由于改变了Delay的数值,导致频率变化

3.每个数码管递增显示0——9。

原理同一,靠循环显示出0、1、2、3、4、5、6、7、8、9。

六.实验总结

1.由于数码管为共阳极,小数点为最高位,A为最低位,所以显示内容一定要计算正确。

2.循环条件要选择正确。

实验二 键盘输入与I/O实验

一.实验目的

1.学习键盘驱动原理;

2.掌握通过CPU的I/O扩展键盘的方法。

二.实验原理

1.键盘实现方案

(1)采用专门的芯片实现键盘扫描

(2)采用软件实现键盘扫描

2.软键盘实现方案

         当开关打开时,通过处理器的I/O 口的一个上拉电阻提供逻辑1;当开关闭合时,处理器的I/O 口的输入将被拉低到逻辑0。

3.按键抖动

         开关并不完善,因为当它们被按下或者被释放时,并不能够产生一个明确的1或者0。尽管触点可能看起来稳定而且很快地闭合,但与微处理器快速的运行速度相比,这种动作是比较慢的。当触点闭合时,其弹起就像一个球。弹起效果将产生如下图所示的好几个脉冲。弹起的持续时间通常将维持在5ms~30ms 之间。

4.矩阵键盘电路

(1)一个瞬时接触开关(按钮)放置在每一行与每一列的交叉点。每一行由一个输出端口的一位驱动,每一列由一个电阻器上拉且供给输入端口一位。

(2)键盘扫描过程就是让微处理器按有规律的时间间隔查看键盘矩阵,以确定是否有键被按下。

(3)一旦处理器判定有一个键按下,键盘扫描软件将过滤掉抖动并且判定哪个键被按下。

(4)每个键被分配一个称为扫描码的唯一标识符。应用程序利用该扫描码,根据按下的键来判定应该采取什么行动,换句话说,扫描码将告诉应用程序按下哪个键。

5.键盘扫描算法

(1)初始化:所有的行(输出端口)被强行设置为低电平。

(2)在没有任何键按下时,所有的列(输入端口)将读到高电平。

(3)任何键的闭合将造成其中的一列变为低电平。

(4)一旦检测到有键被按下,就需要找出是哪一个键。过程很简单,微处理器只需在其中一行上输出一个低电平。如果它在输入端口上发现一个0值,微处理器就知道在所选择行上产生了键的闭合。

6. JXARM9-2440的键盘模块

JXARM9-2440具有4×4的软键盘。原理图如下:

 


三.实验内容及步骤

(一)学习与分析例程中的各个程序以及主要函数,以进一步理解键盘的工作原理。

(二)获取按键值,在串口显示。

(三)使按键按照如图的顺序显示出来。

(四)将键盘按键值在数码管上显示。或自行开发。

步骤:

1) 参照模板工程key(modules\key\key.apj),新建一个工程key,添加相应的文件,并修改key 的工程设置;

2) 创建main.c 并加入到工程key 中;

3) 按照实验内容编写相应程序;

4) 编译key;

5) 下载程序并运行,按键看串口是否有显示;看数码管是否输出相应键值。

四.实验程序

#include "def.h"

#include "2410lib.h"

#include "option.h"

#include "2410addr.h"

#include "interrupt.h"

#define U8 unsigned char

unsigned char segtable[16] = {

    /* 0       1       2       3       4       5       6      7*/

    0xc0,   0xf9,   0xa4,   0xb0,   0x99,   0x92,   0x82,   0xf8,

    /* 8       9      A        B       C       D       E      F*/

    0x80,   0x90,   0x88,   0x83,   0xc6,   0xa1,   0x86,   0x8e,

};

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

// Function name     : Main

// Description      : JXARM9-2410 键盘实验主程序

//                    实现功能:

// Return type          : void

// Argument         : void

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

void Main(void)

{

         /* 配置系统时钟 */

    ChangeClockDivider(2,1);

    U32 mpll_val = 0 ;

    mpll_val = (92<<12)|(1<<4)|(1);

    ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);

    /* 初始化端口 */

    Port_Init();

    /* 初始化串口 */

    Uart_Init(0,115200);

    Uart_Select(0);

    /* 打印提示信息 */

         PRINTF("\n---键盘测试程序---\n");

         PRINTF("\n请将UART0与PC串口进行连接,然后启动超级终端程序(115200, 8, N, 1)\n");

         /* 开始回环测试 */

         while(1)

         {

                  unsigned char ch;

                  int i;

             ch=Key_GetKeyPoll();

                 

                  if(ch != 0)                           //按键值在数码管上显示

                  {

                           PRINTF("\r'%c'键按下", ch);

                           *((U8*)0x20007000) = 0x3B;

                          

                           if(ch>='9')        

                           {

                                    *((U8*)0x20006000)=segtable[(int)ch-0x41+10];

                           }

                           else        

                           {

                                    *((U8*)0x20006000)=segtable[(int)ch-0x30];

                           }

                          

                  }

         }

}

使按键如图所示显示,在keyboard.c中更改以下程序的数值便可达到效果

char key_get_char(int row, int col)

{

         char key = 0;

        

         switch( row )

         {

         case 0:

                  if((col & 0x01) == 0) key = 'F';

                  else if((col & 0x02) == 0) key = 'E';

                  else if((col & 0x04) == 0) key = 'D';

                  else if((col & 0x08) == 0) key = 'C';

                  break;

         case 1:

                  if((col & 0x01) == 0) key = 'B';

                  else if((col & 0x02) == 0) key = '9';

                  else if((col & 0x04) == 0) key = '6';

                  else if((col & 0x08) == 0) key = '3';

                  break;

         case 2:

                  if((col & 0x01) == 0) key = 'A';

                  else if((col & 0x02) == 0) key = '8';

                  else if((col & 0x04) == 0) key = '5';

                  else if((col & 0x08) == 0) key = '2';

                  break;

         case 3:

                  if((col & 0x01) == 0) key = '0';

                  else if((col & 0x02) == 0) key = '7';

                  else if((col & 0x04) == 0) key = '4';

                  else if((col & 0x08) == 0) key = '1';

                  break;

         default:

                  break;

         }

         return key;

}

五.结果及分析

 1.任意按键,串口可显示出按键值;更改为如图所示后,依然显示正确。

    加入了获取按键值的函数,可将按键值传输到串口。

 2. 按键值可显示在数码管上

    将获取的按键值转换成十六进制数进行显示。

六.实验总结

     了解keyboard.c中按键排列顺序,字符转换十六进制数时要转换正确。

实验三 中断实验

一.实验目的

1.了解中断的作用;

2.掌握嵌入式系统中断的处理流程;

3.掌握ARM中断编程。

二.实验原理

1.当CPU进行主程序操作时,外设的数据已存入输入端口的数据寄存器;或端口的数据输出寄存器已空,由外设通过接口电路向CPU发出中断请求信号,CPU在满足一定的条件下,暂停执行当前正在执行的主程序,转入执行相应能够进行输入/输出操作的子程序,待输入/输出操作执行完毕之后CPU再返回并继续执行原来被中断的主程序。这样CPU就避免了把大量时间耗费在等待、查询状态信号的操作上,使其工作效率得以大大地提高。

三.实验内容及步骤

(一)学习例程,对其关键程序与设置进行分析。

(二)编写中断处理程序,处理外部中断2,3,控制LED灯闪烁或数码管显示。

1、当外部中断2发生时,使8个LED在亮灭间切换;

2、当外部中断3发生时,使8个LED等依次亮一下。

3、当中断发生时,控制数码管显示。

步骤:

1) 参照模板工程,新建一个工程interrupt,添加相应的文件,并修改interrupt 的工程设置;

2) 加入如下文件到interrupt 中:common\2440lib.c、;asm\2440init.s、asm\2440slib.s 和common\interrupt.c。

3) 根据实验内容编写外部中断2,3的中断处理程序,并保存为main.c 文件,将该文件加入到工程中;

4) 编译、下载并运行程序。

四.实验程序

#include "def.h"

#include "2410lib.h"

#include "option.h"

#include "2410addr.h"

#include "interrupt.h"

/* functions */

void eint2_isr(void) __attribute__ ((interrupt("IRQ")));;

void eint3_isr(void) __attribute__ ((interrupt("IRQ")));;

void delay();

/* variables */

int dither_count2 = 0;

int dither_count3 = 0;

static int nLed = 0;

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

// Function name     : Main

// Description      : JXARM9-2410 中断实验主程序

//                    完成功能:

//                        外部中断按键引发中断

// Return type          : void

// Argument         : void

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

void Main(void)

{

         /* 配置系统时钟 */

    ChangeClockDivider(2,1);

    U32 mpll_val = 0 ;

    mpll_val = (92<<12)|(1<<4)|(1);

    ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);

        

         /* 中断初始化 */

    Isr_Init();

    /* 初始化端口 */

    Port_Init();

   

    /* 初始化串口 */

    Uart_Init(0,115200);

    Uart_Select(0);

    /* 打印提示信息 */

         PRINTF("\n---外部中断测试程序---\n");

         PRINTF("\n请将UART0与PC串口进行连接,然后启动超级终端程序(115200, 8, N, 1)\n");

         PRINTF("\n外部中断测试开始\n");

         /* 请求中断 */

         Irq_Request(IRQ_EINT2, eint2_isr);                          //中断选择

    //Irq_Request(IRQ_EINT3, eint3_isr);

    /* 使能中断 */

    Irq_Enable(IRQ_EINT2);

    //Irq_Enable(IRQ_EINT3);

   

    dither_count2 = 0;

    dither_count3 = 0;

    while(1)

    {

             delay();

             dither_count2++;

             dither_count3++;

    }

}

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

// Function name     : eint2_isr

// Description      : EINT2中断处理程序

// Return type          : int

// Argument         : void

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

void eint2_isr(void)

{

         Irq_Clear(IRQ_EINT2);       

    if(dither_count2 > 10)

    {

              dither_count2 = 0;

        

         (*(U8*)0x20007000)=0x0;                                  //中断发生时,数码管显示

         (*(U8*)0x20006000)=0x80;

        

         (*(U8*)0x20005000)=nLed;                                //LED亮灭切换

         nLed=~nLed;

         }

}

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

// Function name     : eint3_isr

// Description      : EINT3中断处理程序

// Return type          : int

// Argument         : void

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

void eint3_isr(void)

{

         Irq_Clear(IRQ_EINT3);       

    if(dither_count3 > 10)

    {

              dither_count3 = 0;

             

         (*(U8*)0x20007000)=0x0;                                                    //中断发生时,数码管显示

         (*(U8*)0x20006000)=0x90;

        

         (*(U8*)0x20005000)=0x01;delay();                            //LED依次亮一下

         (*(U8*)0x20005000)=0x02;delay();

         (*(U8*)0x20005000)=0x04;delay();

         (*(U8*)0x20005000)=0x08;delay();

         (*(U8*)0x20005000)=0x10;delay();

         (*(U8*)0x20005000)=0x20;delay();

         (*(U8*)0x20005000)=0x40;delay();

         (*(U8*)0x20005000)=0x80;delay();

         }

}

void delay()

{

         int index = 0;

        

         for ( index = 0 ; index < 20000; index++);

}

五.结果及分析

1.中断2发生时,LED亮灭切换。

2.中断3发生时,LED从右依次亮灭。

3.中断发生,数码管显示数字。

    加入中断使能语句,可使中断2和中断3发生,LED的地址为20005000,其余和之前原理相同,在中断语句部分里面加入。

六.实验总结

    同时只能有一个中断发生

实验四 A/D实验

一.实验原理

1.了解模数转换的基本原理。

2.掌握模数转换的编程方法。

二.实验原理

         要将模拟量转换成数字信号需经采样——>量化——>编码三个基本过程(数字化过程)。

(1)采样:按采样定理对模拟信号进行等时间间隔采样,将得到的一系列时域上的样值去代替u=f(t),即用u0、u1、…un代替u=f(t)。这些样值在时间上是离散的值,但在幅度上仍然是连续模拟量。

 

(2)量化:

在幅值上再用离散值来表示。方法是用一个量化因子Q去度量u0、u1、…,便得到整量化的数字量。

         u0=2.4Q 2Q

         u1=4.0Q 4Q

         u2=5.2Q 5Q

         u3=5.8Q 5Q

(3)编码:

将整量化后的数字量进行编码,以便读入和识别;编码仅是对数字量的一种处理方法。

例如:Q=0.5V/格,设用三位(二进编码)

    

通道0和通道1的模拟输入信号可通过实验箱的可调电阻AIN0、AIN1调节。

三.实验内容及步骤

(一)学习例程,对其关键程序与设置进行分析。

(二)

1、通过可变电阻改变模拟量输入,补充程序将模拟输入进行采集和转换,观查显示结果(在串口显示);

2、将转换后的电压值结果显示在LED上和串口上(如2.345)。

3、 自行开发。

步骤:

1) 参照模板工程ad(modules\ad\ad.apj),新建一个工程ad,添加相应的文件,并修改ad的工程设置;创建main.c 并加入到工程ad 中;

2) 根据内容编程;

3) 编译、链接、调试、运行。

四.实验程序

#include "def.h"

#include "2410lib.h"

#include "option.h"

#include "2410addr.h"

#include "interrupt.h"

void delay(int time) {

    int i;

         int delayLoopCount=1000;

    for(;time>0;time--);

                  for(i=0;i<delayLoopCount;i++);

}

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

// Function name     : Main

// Description      : JXARM9-2410 A/D采样实验主程序

//                    实现功能:

//                        实现JXRAM9-2410的模数转换

//                        JXARM9-2410 UART0 <==> PC COM

// Return type          : void

// Argument         : void

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

void Main(void)

{

         /* 配置系统时钟 */

    ChangeClockDivider(2,1);

    U32 mpll_val = 0 ;

    mpll_val = (92<<12)|(1<<4)|(1);

    ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);

   

    /* 初始化端口 */

    Port_Init();

   

    /* 初始化串口 */

    Uart_Init(0,115200);

    Uart_Select(0);

   

    /* 打印提示信息 */

         PRINTF("\n---AD采样程序---\n");

         PRINTF("\n请将UART0与PC串口进行连接,然后启动超级终端程序(115200, 8, N, 1)\n");

         PRINTF("\n从现在开始您将在超级终端上看到采样值,旋动旋钮AIN2和AIN3改变模拟输入\n");

    /* 开始测试 */

    Test_Adc();

         while(1)

         {

         }

}

#define ADC_FREQ 2500000

#define u8 unsigned char

unsigned char segtable[16] =

{

    /* 0       1       2       3       4       5       6      7*/

    0xc0,   0xf9,   0xa4,   0xb0,   0x99,   0x92,   0x82,   0xf8,

    /* 8       9      A        B       C       D       E      F*/

    0x80,   0x90,   0x88,   0x83,   0xc6,   0xa1,   0x86,   0x8e,

};

int ReadAdc(int ch);         //Return type is int, Declare Prototype function

void Test_Adc(void)

{

    int i;

    int n1,n2,n3,n4,z;

    float b0,z1;

    int a0=0,a1=0,a2=0,a3=0,a4=0,a5=0,a6=0,a7=0; //Initialize variables

   

    PRINTF("----------AD测试--------\n");

    PRINTF("旋动AIN0, AIN1旋钮改变模拟输入,任意键退出\n");

       

    while(1)

    {

                  a0=Adc_Get_Data(0,ADC_FREQ);                             //模拟输入采集

                  b0=(float)a0/1024*3.3;                                                //模拟输入转换并输出

             PRINTF("\rAIN0: %04d,NUM0: %04f",a0,b0);

            

             z=b0*1000;                                                            //将转换后的的电压值在数码管上输出

             n4=z%10;

             n3=(z/10)%10;

             n2=(z/100)%10;

             n1=z/1000;

             *((u8*)0x20007000)=0x3e;                                                  

                  *((u8*)0x20006000)=segtable[n4];

                  delay(10000);

                  *((u8*)0x20007000)=0x3d;

                  *((u8*)0x20006000)=segtable[n3];

                  delay(10000);

                  *((u8*)0x20007000)=0x3b;

                  *((u8*)0x20006000)=segtable[n2];

                  delay(10000);

                  *((u8*)0x20007000)=0x37;

                  *((u8*)0x20006000)=(segtable[n1]&0x7f);

                  delay(10000);

            

    }

    rADCCON=(0<<14)|(19<<6)|(7<<3)|(1<<2);  //stand by mode to reduce power consumption  

         PRINTF("\n");

    PRINTF("--------AD测试结束------\n\n");

}

五.结果及分析

1.扭动旋钮改变电阻,串口上输出模拟量及转换后的输出电压值。

2.转换后的电压值在数码管上显示。

    语句a0=Adc_Get_Data(0,ADC_FREQ)可获取通道0的模拟输入值,然后通过公式(float)a0/1024*3.3可得到数字输出值。可在串口上显示。再根据算式将各个位数字取出,便可实现在数码管上显示。

六.实验总结

    将各位取出时,可选择小数点后的位数,导致n的数量增多。

    在将模拟量转换为数字量的时候,要进行float类型强制转换。

实验五 系统时钟实验

一.实验目的

1.了解实时时钟在嵌入式系统中的作用。

2.掌握实时时钟的使用。

二.实验原理

在一个嵌入式系统中,实时时钟单元可以提供可靠的时钟,包括时分秒和年月日;即使在系统处于关机状态下它也能够正常工作(通常采用后备电池供电)。

三.实验内容及步骤

(一)学习与分析实验例程,学习时钟寄存器的设置;

(二)

 1.补充程序,设置与修改当前的日期和时间;实现闹钟告警功能(设05S时报警),使能秒时钟告警 ;

2.将时分秒在数码管上显示出来。

3.自行开发。

步骤:

(1)参照模板工程rtc(modules\rtc\rtc.apj),新建一个工程rtc,添加相应的文件,并修改rtc的工程设置;

(2)创建main.c并加入到工程rtc中;

(3)根据内容编程。编译rtc,下载程序并运行,通过超级终端和数码管看输出结果。

四.实验程序

#include "def.h"

#include "2410lib.h"

#include "option.h"

#include "2410addr.h"

#include "interrupt.h"

/* 表示日期、时间的数据结构 */

typedef struct ST_DATE

{

         short       year;       // 年

         char mon;        // 月

         char day;        // 日

         char week_day;   // 星期

         char hour;       // 时

         char min;        // 分

         char sec;        // 秒

} st_date;

void display();

void delay(int time);

extern unsigned char seg7table[16];

unsigned char loc[6]={

  /* 从左到右的数码管位选 */

  0x1f,0x2f,0x37,0x3b,0x3d,0x3e};

/* 全局变量 */

int led_index = 0;

int ext0_count = 0;

int table[6]={0};

/* functions */

void rtc_tick_isr(void) __attribute__ ((interrupt("IRQ")));;

void rtc_int_isr(void) __attribute__ ((interrupt("IRQ")));;

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

// Function name     : rtc_set_date

// Description      : 修改实时时钟当前时间、日期

// Return type          : void

// Argument         : p_date, 待设置的日期

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

void rtc_set_date(st_date* p_date)

{

    rRTCCON  = 0x01;

    rBCDYEAR = p_date->year;

    rBCDMON  = p_date->mon;

    rBCDDAY  = p_date->day;

    rBCDDATE = p_date->week_day;

    rBCDHOUR = p_date->hour;

    rBCDMIN  = p_date->min;

    rBCDSEC  = p_date->sec;

    rRTCCON  = 0x00;

}

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

// Function name     : rtc_get_date

// Description      : 获取实时时钟当前时间、日期

// Return type          : void

// Argument         : p_date, 返回日期的指针

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

void rtc_get_date(st_date* p_date)

{

    rRTCCON  = 0x01;

   

    p_date->year   =      rBCDYEAR ;

    p_date->mon            =      rBCDMON  ;

    p_date->day             =      rBCDDAY  ;

    p_date->week_day=       rBCDDATE ;

    p_date->hour  =      rBCDHOUR ;

    p_date->min             =      rBCDMIN  ;

    p_date->sec              =      rBCDSEC  ;

    rRTCCON  = 0x00;

}

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

// Function name     : rtc_tick_init

// Description      : 初始化S3C2410的TICK定时器

// Return type          : void

// Argument         : tick, 设置的TICK频率(时钟滴答的周期为 (1+tick)/128秒)

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

void rtc_tick_init( char tick )

{

    Irq_Request(IRQ_TICK, rtc_tick_isr);

   

    rRTCCON   = 0x0;            //No reset[3], Merge BCD counters[2], BCD clock select XTAL[1], RTC Control disable[0]

    rTICNT  = (tick&0x7f)|0x80;           /*TICK 中断使能,周期为(1+tick)/128秒*/  

    Irq_Enable(IRQ_TICK);  

}

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

// Function name     : rtc_alarm_set

// Description      : 设置S3C2410的告警时间以及方式

// Return type          : void

// Argument         : p_date, 告警的时间

//                    mode, 告警模式

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

void rtc_alarm_set(st_date* p_date, unsigned char mode)

{

    Irq_Request(IRQ_RTC, rtc_int_isr);

   

    rRTCCON  = 0x01;

   

    rALMYEAR = p_date->year;

    rALMMON  = p_date->mon;

    rALMDATE = p_date->day;

    rALMHOUR = p_date->hour;

    rALMMIN  = p_date->min;

    rALMSEC  = p_date->sec;

   

    rRTCALM  = mode;

   

    rRTCCON  = 0x00;

    Irq_Enable(IRQ_RTC);  

}

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

// Function name     : Main

// Description      : JXARM9-2410 实时时钟实验主程序

//                    完成功能:

//                        时钟滴答:每秒钟刷新数码管显示

//                        设置当前日期、时间

//                        动态刷新当前日期、时间,通过串口打印出来

//                        时间告警功能:每分钟的第5秒告警,并进行跑马灯显示

// Return type          : void

// Argument         : void

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

void Main(void)

{

         int old_index ;

        

         st_date m_date;

        

         /* 配置系统时钟 */

    ChangeClockDivider(2,1);

    U32 mpll_val = 0 ;

    mpll_val = (92<<12)|(1<<4)|(1);

    ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);

        

         /* 中断初始化 */

    Isr_Init();

    /* 初始化端口 */

    Port_Init();

   

    /* 初始化串口 */

    Uart_Init(0,115200);

    Uart_Select(0);

    /* 打印提示信息 */

         PRINTF("\n---实时时钟测试程序---\n");

         PRINTF("\n请将UART0与PC串口进行连接,然后启动超级终端程序(115200, 8, N, 1)\n");

         PRINTF("\n实时时钟测试开始\n");

         /* 采用BCD编码,如20##年需要设置的值为0x2004 */

         m_date.year = 0x15;                        m_date.mon = 0x05;

       m_date.day = 0x07;

       m_date.week_day = 0x04;

       m_date.hour = 0x20;

       m_date.min = 0x50;

       m_date.sec = 0x55;

    /* 修改当前日期和时间 */

    rtc_set_date(&m_date);

   

    m_date.sec               =      0x05;                 //设置报警时间

    /* 设置告警的时间及方式,0x41表示使能RTC告警,以及使能秒时钟告警 */

          rtc_alarm_set(&m_date,0x41);

          rtc_tick_init(127);

        

         old_index = led_index;

     PRINTF("\r\n\r\n");

    

    while(1)

    {

             if(old_index != led_index)                  /* 每隔一秒更新一次数据                              */

             {

                  rtc_get_date(&m_date);

                  old_index = led_index;

                            exchange(&m_date);

                  display();

                  PRINTF(                               /* 时钟数据为BCD码格式,以16进制显示 */

                                    "\b\b\b\b\b\b\b\b%02x:%02x:%02x", m_date.hour, m_date.min, m_date.sec);

         }

    };

}

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

// Function name     : rtc_tick_isr

// Description      : TICK中断处理程序,程序中设置每秒钟引发一次中断

// Return type          : int

// Argument         : void

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

void rtc_tick_isr(void)

{

         Irq_Clear(IRQ_TICK);         /* 清除TICK中断 */

//      *((unsigned char*) 0x02000006) = 0x00;        

//  *(unsigned char*)0x02000004 = seg7table[led_index%10]; 

    

     led_index++;

}

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

// Function name     : rtc_int_isr

// Description      : rtc中断处理程序,程序中设置每分钟的第5秒引发该中断

// Return type          : int

// Argument         : void

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

void rtc_int_isr(void)

{

         Irq_Clear(IRQ_RTC);          /*清除RTC中断                                                     */

   

 // if(ext0_count&1)       

 //             *(unsigned char*)0x2000000 = 0x0f; 

 // else

 //          *(unsigned char*)0x2000000 = 0xff; 

             

     ext0_count++;

    

     PRINTF("\r\nAlarm\r\n                  ");

    

}

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

 //name:         exchange

 //description:  将BCD码转化为数组形式

 //return type:  void

 //argument:     p_data

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

int exchange(st_date* p_date) {

  table[0]=(p_date->hour & 0xf0)>>4;                         //控制时分秒的显示

  table[1]=p_date->hour & 0x0f;

  table[2]=(p_date->min & 0xf0)>>4;

  table[3]=p_date->min & 0x0f;

  table[4]=(p_date->sec & 0xf0)>>4;

  table[5]=p_date->sec & 0x0f;

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

 //name:         display

 //description:  数码管显示

 //return type:  void

 //argument:     void

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

void display()                                                 //数码管显示

{

  int i,count=90;                       // 调节count使显示正好在1s内

  while(count--) {

    for(i=0;i<6;i++) {

      *((U8*)0x20007000)=loc[i];

      *((U8*)0x20006000)=seg7table[table[i]];            /*调用数组str1*/

      delay(1);

    }

  }

  *((U8*)0x20007000)=0x3f;              // 关数码管

}   /*end for display*/

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

/* Function name: 循环延时子程序

/* Description: 循环‘time’次

/* Return type: void

/* Input type: int time

/* Argument: 循环延时计数器

*/

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

void delay(int time) {

  int i;

  int delayLoopCount=1000;

  for(;time>0;time--)

    for(i=0;i<delayLoopCount;i++);

}  

五.结果及分析

    运行程序,串口和数码管会显示时间,但是不同步,当每分钟的第三秒,串口显示报警。

六.实验总结

    由于延迟或者其他原因,串口时间与数码管时间不同步,而且报警时间与预期的也不同步。

实验六 看门狗实验

一.实验目的

1.了解WATCHDOG的作用。

2.掌握WATCHDOG定时器的使用方法。

二.实验原理

         看门狗定时器(WDT,Watch Dog Timer)是单片机的一个组成部分,它实际上是一个计数器,一般给看门狗一个大数,程序开始运行后看门狗开始倒计数。如果程序运行正常,过一段时间CPU应发出指令让看门狗复位,重新开始倒计数。如果看门狗减到0就认为程序没有正常工作,强制整个系统复位。

         看门狗定时器是单片机的一个组成部分,在单片机程序的调试和运行中都有着重要的意义。它的主要功能是在发生软件故障时,通过使器件复位(如果软件未将器件清零)将单片机复位。也可以用于将器件从休眠或空闲模式唤醒,看门狗定时器对微控制器提供了独立的保护系统,当系统出现故障时,在可选的超时周期之后,看门狗将以RESET信号作出响应,像x25045就可选超时周期为1.4秒、600毫秒、200毫秒三种。当你的程序死机时,x25045就会使单片机复位。

三.实验内容及步骤

(一)学习与分析例程;

(二)

1.在时钟实验的基础上增加看门狗代码,使看门狗的周期为2S左右,打开看门狗复位功能,不喂狗,观察是否复位;

2.使看门狗的周期为2S左右,打开看门狗复位功能,每秒喂狗一次,观察是否复位;

3.编程,使看门狗的周期为2S左右,打开看门狗复位功能,每3S喂狗一次,观察是否复位;

4.自行发挥

步骤:

1) 参照模板工程watchdog(modules\rtc\watchdog.apj),新建一个工程watchdog,添加相应的文件,并修改watch 的工程设置;

2) 创建main.c 并加入到工程watch 中;

3) 根据内容编程;

4) 编译main,下载程序并运行,通过超级终端看是否复位;

四.实验程序

#include "def.h"

#include "2410lib.h"

#include "option.h"

#include "2410addr.h"

#include "interrupt.h"

extern unsigned char seg7table[];

/* 表示日期、时间的数据结构 */

typedef struct ST_DATE

{

         short       year;       // 年

         char mon;        // 月

         char day;        // 日

         char week_day;   // 星期

         char hour;       // 时

         char min;        // 分

         char sec;        // 秒

} st_date;

/* 全局变量 */

int led_index = 0;

int ext0_count = 0;

int flag=0;

/* functions */

void rtc_tick_isr(void) __attribute__ ((interrupt("IRQ")));;

void rtc_int_isr(void) __attribute__ ((interrupt("IRQ")));;

#define WDT_ENABLE                       (0x01<<5)

#define WDT_INT_ENABLE              (0x01<<2)

#define WDT_RST_ENABLE              (0x01<<0)        

#define WDT_CLK_SEL                      (0X3    <<3)           /* 1/128 */

#define WDT_PRE_SCALER              ((PCLK/1000000-1)   <<8)               /* 49    */

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

// Function name     : watchdog_init

// Description      : 看门狗初始化

// Return type          : void

// Argument         :

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

void watchdog_init()

{

         rWTCNT = 8448 * 2;                  /* 设置看门狗初始值 */

         rWTCON = WDT_ENABLE | WDT_RST_ENABLE | WDT_CLK_SEL | WDT_PRE_SCALER;        /* 打开看门狗 */          /* 打开看门狗 */

}

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

// Function name     : rtc_set_date

// Description      : 修改实时时钟当前时间、日期

// Return type          : void

// Argument         : p_date, 待设置的日期

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

void rtc_set_date(st_date* p_date)

{

    rRTCCON  = 0x01;

    rBCDYEAR = p_date->year;

    rBCDMON  = p_date->mon;

    rBCDDAY  = p_date->day;

    rBCDDATE = p_date->week_day;

    rBCDHOUR = p_date->hour;

    rBCDMIN  = p_date->min;

    rBCDSEC  = p_date->sec;

    rRTCCON  = 0x00;

}

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

// Function name     : rtc_get_date

// Description      : 获取实时时钟当前时间、日期

// Return type          : void

// Argument         : p_date, 返回日期的指针

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

void rtc_get_date(st_date* p_date)

{

    rRTCCON  = 0x01;

   

    p_date->year   =      rBCDYEAR ;

    p_date->mon            =      rBCDMON  ;

    p_date->day             =      rBCDDAY  ;

    p_date->week_day=       rBCDDATE ;

    p_date->hour  =      rBCDHOUR ;

    p_date->min             =      rBCDMIN  ;

    p_date->sec              =      rBCDSEC  ;

   

    rRTCCON  = 0x00;

}

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

// Function name     : rtc_tick_init

// Description      : 初始化S3C2410的TICK定时器

// Return type          : void

// Argument         : tick, 设置的TICK频率(时钟滴答的周期为 (1+tick)/128秒)

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

void rtc_tick_init( char tick )

{

    Irq_Request(IRQ_TICK, rtc_tick_isr);

   

    rRTCCON   = 0x0;            //No reset[3], Merge BCD counters[2], BCD clock select XTAL[1], RTC Control disable[0]

    rTICNT  = (tick&0x7f)|0x80;           /*TICK 中断使能,周期为(1+tick)/128秒*/  

    Irq_Enable(IRQ_TICK);  

}

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

// Function name     : rtc_alarm_set

// Description      : 设置S3C2410的告警时间以及方式

// Return type          : void

// Argument         : p_date, 告警的时间

//                    mode, 告警模式

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

void rtc_alarm_set(st_date* p_date, unsigned char mode)

{

    Irq_Request(IRQ_RTC, rtc_int_isr);

   

    rRTCCON  = 0x01;

   

    rALMYEAR = p_date->year;

    rALMMON  = p_date->mon;

    rALMDATE = p_date->day;

    rALMHOUR = p_date->hour;

    rALMMIN  = p_date->min;

    rALMSEC  = p_date->sec;

   

    rRTCALM  = mode;

   

    rRTCCON  = 0x00;

    Irq_Enable(IRQ_RTC);  

}

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

// Function name     : Main

// Description      : JXARM9-2410 看门狗实验主程序

//                    完成功能:

//                        在实时时钟实验的基础上添加看门狗功能,并在时钟滴答

//                        中断中实现喂狗处理.

//      

// Return type          : void

// Argument         : void

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

void Main(void)

{

         int old_index ;

         st_date m_date;

         /* 配置系统时钟 */

    ChangeClockDivider(2,1);

    U32 mpll_val = 0 ;

    mpll_val = (92<<12)|(1<<4)|(1);

    ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);

        

         /* 中断初始化 */

    Isr_Init();

    /* 初始化端口 */

    Port_Init();

   

    /* 初始化串口 */

    Uart_Init(0,115200);

    Uart_Select(0);

    /* 打印提示信息 */

         PRINTF("\n---看门狗测试程序---\n");

         PRINTF("\n请将UART0与PC串口进行连接,然后启动超级终端程序(115200, 8, N, 1)\n");

         PRINTF("\n看门狗测试开始\n");

         /* 采用BCD编码,如20##年需要设置的值为0x2004 */

    m_date.year             =      0x2000+0x15 ;

    m_date.mon             =      0x05 ;

    m_date.day              =      0x07 ;

    m_date.week_day  =      0x04 ;

    m_date.hour            =      0x20 ;

    m_date.min              =      0x35 ;

    m_date.sec               =      0x00 ;

   

    /* 修改当前日期和时间 */

    rtc_set_date(&m_date);

   

    m_date.sec               =      0x05 ;

   

    /* 设置告警的时间及方式,0x41表示使能RTC告警,以及使能秒时钟告警 */

    rtc_alarm_set(&m_date, 0x41);

        

         rtc_tick_init(127);

        

        

         watchdog_init();                                 //打开看门狗复位功能

         old_index = led_index;

     PRINTF("请在2秒内喂狗,否则系统将在约2秒后复位\n\n");

    

    while(1)

    {

             if(old_index != led_index)                  /* 每隔一秒更新一次数据                              */

             {

                  rtc_get_date(&m_date);

                  old_index = led_index;

                          

                  PRINTF(                               /* 时钟数据为BCD码格式,以16进制显示 */

                                    "\b\b\b\b\b\b\b\b%02x:%02x:%02x", m_date.hour, m_date.min, m_date.sec);

         }

    };

}

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

// Function name     : rtc_tick_isr

// Description      : TICK中断处理程序,程序中设置每秒钟引发一次中断

//                    为避免看门狗复位在此处喂狗

// Return type          : int

// Argument         : void

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

void rtc_tick_isr(void)

{

         Irq_Clear(IRQ_TICK);         /* 清除TICK中断 */

     /* 喂狗 */

    if(flag>=3)                           //此处更改喂狗的周期

     {

             flag=0;

             rWTCNT=8448 * 2;

              PRINTF("\r\n喂狗成功\r\n");

     }

}

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

// Function name     : rtc_int_isr

// Description      : rtc中断处理程序,程序中设置每分钟的第5秒引发该中断

// Return type          : int

// Argument         : void

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

void rtc_int_isr(void)

{

         Irq_Clear(IRQ_RTC);          /*清除RTC中断                                                     */

   

//    if(ext0_count&1) 

//                    *(unsigned char*)0x2000000 = 0x0f; 

//           else

//                    *(unsigned char*)0x2000000 = 0xff; 

             

     ext0_count++;

     PRINTF("\r\nAlarm\r\n                  ");

}

五.结果及分析

1.打开看门狗复位功能,不喂狗,看门狗复位。

2.使看门狗周期为2s左右,打开看门狗复位功能,每秒喂狗一次,看门狗不复位。

3.每3s喂狗一次,看门狗复位。

    喂狗相当于给看门狗一个使能信号,阻止看门狗复位。但当不喂狗或者喂狗的周期大于看门狗的周期时,看门狗也会复位。

六.实验总结

    正确区分看门狗复位与机器故障引起的复位,正确使用喂狗条件与周期。

实验七 PWM实验

一.实验目的

1.了解PWM的基本原理。

2.掌握PWM控制的编程方法。

二.实验原理

1.PWM是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。

         许多微控制器内部都包含PWM控制器。一般都可以选择接通时间和周期。占空比是接通时间与周期之比;调制频率为周期的倒数。

         设置提供调制方波的片上定时器/计数器的周期;在PWM控制寄存器中设置接通时间;启动定时器。

2.音乐中的音名与频率的对应关系

三.实验内容及步骤

(一)学习与分析例程;

(二)

1.编写程序对PWM控制器输出8000Hz 2/3占空比的数字信号控制峰鸣器;

2.编写程序改变PWM控制器输出频率,如频率从4000HZ到14000HZ, 使用2/3的占空比;

3.编写程序改变PWM控制器输出占空比,如频率1000HZ, 使用1/100 - 95/100的占空比。

4.编写程序实现一句音乐。

步骤:

(1)新建一个工程,添加相应的文件,并修改相应的工程设置;

(2)创建main.c文件,将该文件加入到工程中;

(3)根据内容编写程序输出到蜂鸣器;

(4)编译、下载、运行、调试程序、听蜂鸣器输出结果;

四.实验程序

#include "def.h"

#include "2410lib.h"

#include "option.h"

#include "2410addr.h"

#include "interrupt.h"

void test_pwm();

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

// Function name     : Main

// Description      : JXARM9-2410 PWM实验主程序

//                    实现功能:

//                        实现JXARM9-2410 PWM方式控制蜂鸣器

// Return type          : void

// Argument         : void

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

void Main(void)

{

         unsigned char data[6] = {0, 1, 2, 3, 4, 5};

         /* 配置系统时钟 */

    ChangeClockDivider(2,1);

    U32 mpll_val = 0 ;

    mpll_val = (92<<12)|(1<<4)|(1);

    ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);

   

    /* 初始化端口 */

    Port_Init();

   

    /* 初始化串口 */

    Uart_Init(0,115200);

    Uart_Select(0);

   

    /* 打印提示信息 */

         PRINTF("\n---蜂鸣器测试程序---\n");

        

         /* 端口设置 */

         rGPBUP  = rGPBUP  & ~(0x1f)     | 0x1f;         //GPB4 ~ 0

    rGPBCON = rGPBCON & ~(0x3ff)    | 0x2aa;        //Function Setting TCLK0, TOUT3 ~ 0  

    rGPGUP  = rGPGUP  & ~(0x800)    | 0x800;        //GPG11

    rGPGCON = rGPGCON & ~(0xc00000) | 0xc00000;     //TCLK1

    rGPHUP  = rGPHUP  & ~(0x200)    | 0x200;        //GPH9

    rGPHCON = rGPHCON & ~(0x3<<18)  | (0x2<<18);    //CLKOUT0   

    rMISCCR = rMISCCR & ~(0xf0)     | 0x40;         //Select PCLK with CLKOUT0

    /* 开始测试 */

         test_pwm();

         while(1);

}

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

// Function name     : test_pwm

// Description      : 测试PWM,通过蜂鸣器输出脉冲

// Return type          : int

// Argument         : void

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

void test_pwm()

{

         rTCFG0 = 0xff;

         rTCFG1 = 0x1;

         int N;

        

    N = PCLK / 256 / 4 / 8000;                 //输出脉冲:频率8000Hz, 2/3占空比

         rTCNTB0 = N;

         rTCMPB0 = 2 * N / 3;

         rTCON = 0x9;

         Delay(100);

    int feq;

         for (feq = 4000; feq <= 14000; feq=feq+1000)

//输出脉冲:频率从4000HZ到14000HZ, 使用2/3的占空比

         {

                  N = PCLK / 256 / 4 / feq;

                  rTCNTB0 = N;

                  rTCMPB0 = 2 * N / 3;

                  rTCON = 0xa;

                  rTCON = 0x9;

                  Delay(100);

                  rTCON = 0x0;

         }

                  N = PCLK / 256 / 4 / 1000;  //输出脉冲:频率1000HZ, 使用1/100 - 95/100的占空比    

    rTCNTB0 = N;

         int i;

         int N1;

         for (i = 1; i <= 19; i++)

         {

                  N1 = i*N / 100;

                  rTCMPB0 = N1;

                  rTCON = 0xa;

                  rTCON = 0x9;

                  Delay(100);

                  rTCON = 0x0;

         }

int  song[38]={659,659,659,659,659,698,659,523,578,659,698,988,523,578,578,659,880,440,523,494,494,659,659,659,659,784,659,698,698,880,698,659,698,698,578,578,698,578};

//德国战车 中低音

for (i=0; i<59; i++)

{

         N=PCLK/256/4/song[i];

         rTCNTB0=N;

         rTCMPB0=2*N/3;

         rTCON=0xa;

         rTCON=0x9;

        

     Delay(50);

        rTCON=0x0;

 }

/* 设置定时器的预分频率值:TIME0/1=255, TIME2/3=0, TIME4/5=0*/

/* 设置定时器的工作模式:中断模式,设置分频率值:TIME0为1/4,其他为1/2*/

/* 输出脉冲:频率从4000HZ到14000HZ, 使用2/3的占空比*/

/* 输出脉冲:频率1000HZ, 使用1/100 - 95/100的占空比*/

}

五.结果及分析

1.运行程序,实验仪器控制蜂鸣器依次产生不同频率的声音。

分析:不同的频率对因不同的声音,控制频率的变化可产生不同的声音。

六.实验总结

1.产生的音乐与实际音乐有差别是因为PWM中,两个音之间的停顿一样,而且频率采取了取舍。

实验八 步进电机实验

一.实验目的

1.了解步进电机的原理以及控制方法。

二.实验原理

         步进电机是将电脉冲信号转变为角位移或线位移的开环控制元件。在非超载的情况下,电机的转速、停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响,即给电机加一个脉冲信号,电机则转过一个步距角。这一线性关系的存在,加上步进电机只有周期性的误差而无累积误差等特点。使得在速度、位置等控制领域用步进电机来控制变得非常的简单。

单三拍方式

         电机的定子上有六个均布的磁极,其夹角是60度。各磁极上套有线圈,按图连成A、B、C三相绕组。设转子上均布40个小齿。所以每个齿的齿距为。三相绕组按A→B→C→A顺序循环通电时,转子会按顺时针方向,以每个通电脉冲转动3度规律步进式转动起来。若改变通电顺序,按A→C→B→A顺序循环通电,则转子就按逆时针方向以每个通电脉冲转动3度律转动。因为每一瞬间只有一相绕组通电,并且按三种通电状态循环通电,故称为单三拍运行方式。三相步进电动机还有两种通电方式,它们分别是双三拍运行,即按AB→BC→CA→AB顺序循环通电的方式,以及单、双六拍运行,即按A→AB→B→BC→C→CA→A顺序循环通电的方式。六拍运行时的步矩角将减小一半。反应式步进电动机的步距角可按下式计算:,式中Er——转子齿数;N——运行拍数,N=km,m为步进电动机的绕组相数,k=1或2。

         本实验的步进电机使用四相式步进电机,工作模式为两相四拍。

         脉冲分配信号:整步模式脉冲分配

三.实验内容及步骤

1.编写程序实现步进电机正转;

2.编写程序实现步进电机反转;

步骤:

1)参照模板工程stepper (modules\stepper\ stepper.apj),新建一个工程stepper,添加相应的文件,并修改stepper的工程设置;

2)创建stepper.c文件,将该文件加入到工程中;

3)编写程序;

4)编译、下载、运行、调试程序、输出结果;

四.实验程序

void delay(int count);

void delay(int time);

#define U8 unsigned char

//ioport unsigned port100e;

/* functions */

void delay(int count);

// TODO

// 整步模式正转脉冲或反转脉冲

void Main(void)

{

         int row = 0;

        

         for( ; ; )

         {

         (*(U8*)0x20002000)= 0x5;

         delay(1000);

         (*(U8*)0x20002000)= 0x9;

         delay(1000);

         (*(U8*)0x20002000)= 0xA;

         delay(1000);

         (*(U8*)0x20002000)= 0x6;

         delay(1000);     // TODO

         (*(U8*)0x20002000)= 0x6;

         delay(1000);

         (*(U8*)0x20002000)= 0xA;

         delay(1000);

         (*(U8*)0x20002000)= 0x9;

         delay(1000);

         (*(U8*)0x20002000)= 0x5;

         delay(1000);

         }

}

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

// Function name     : delay

// Description      : 延时子程序

// Return type          : void

// Argument         : count,延时的数值

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

void delay( int count )

{

         int cnt;

        

         for( count = count; count>0; count--)

                  for( cnt = 0; cnt < 100; cnt++);

}

五.结果及分析

    运行程序后,电机先正转,然后反转。而数码管和LED灯正转时从左向右依次显示,反转时从右向左依次显示。

    电机分为四个方向(不开电扭动可以感觉到),控制四个方向循环即可完成正转反转。LED和数码管显示原理与之前相同。

六.实验总结

    注意电机正转和反转时控制的数组顺序不同,LED和数码管也如此。

实验九 串口通讯实验

一.实验目的

1.掌握ARM的串行口工作原理。

2.学习编程实现ARM的UART通讯。

3.掌握S3C2440寄存器配置方法。

二.实验原理

1.UART(Universal Asynchronous Receiver and Transmitter,通用异步收发器),采用异步串行通信方式。UART以字符为单位进行数据传输,每个字符的传输格式如图所示,包括线路空闲状态(高电平)、起始位(低电平)、5~8位数据位、校验位(可选)和停止位(位数可以是1、1.5或2位)。

2. S3C2440A的UART特性:

(1)基于DMA或基于中断操作的RxD0,TxD0,RxD1,TxD1,RxD2和TxD2

(2)UART通道0,1和2带IrDA 1.0和64字节FIFO

(3)UART通道0和1带nRTS0,nCTS0,nRTS1和nCTS1

(4)支持握手发送/接收

(5)S3C2440A的UART包括了可编程波特率,红外(IR)发送/接收,插入1个或2个停止位,5位、6位、7位或8位的数据宽度以及奇偶校验。

三.实验内容及步骤

(一)学习与分析相关例程,分析有关UART寄存器的设置;

(二)

1.补充程序,实现对串口的初始化和回环测试。接收来自串口(通过超级终端)的字符并将接收到的字符发送到超级终端;

2.在1的基础上将终端输入字符显示在实验箱的数码管上;

3.自行开发,如显示一串字符等。

步骤:

1) 参照模板工程uart(modules\uart\uart.apj),新建一个工程uart,添加相应的文件,

并修改uart 的工程设置;

2) 加入如下文件到uart 中:common\2440lib.c、;asm\2440init.s、asm\2440slib.s。

3) 参照上节内容编写串口操作主函数,并保存为main.c 文件,将该文件加入到工程中;

4) 参考模板工程uart 对uart 工程进行设置,然后编译uart;

5) 将计算机的串口接到教学实验系统的uart0 上;

6) 运行超级终端,选择正确的串口号,并将串口设置为:波特率(115200)、奇偶校验

(None)、数据位数(8)和停止位数(1),无流控,打开串口。

7) 下载程序并运行,如果程序运行正确,在超级终端中输入的数据将回显到超级终端上。

四.实验程序

/* 包含文件 */

#include "def.h"

#include "2410lib.h"

#include "option.h"

#include "2410addr.h"

#include "interrupt.h"\

void showChar(char ch);

void showString(char *str);

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

// Function name     : Main

// Description      : JXARM9-2410 串口通信实验主程序

//                    实现功能:

//                        实现JXRAM9-2410与PC机的串口通讯

//                        JXARM9-2410 UART0 <==> PC COM

// Return type          : void

// Argument         : void

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

void Main(void)

{

         /* 配置系统时钟 */

    ChangeClockDivider(2,1);

    U32 mpll_val = 0 ;

    mpll_val = (92<<12)|(1<<4)|(1);

    ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);

   

    /* 初始化端口 */

    Port_Init();

   

         // TODO  串口初始化

    /* 打印提示信息 */

    Uart_Init(0, 115200);

         Uart_Select(0);

         PRINTF("\n---UART测试程序---\n");

         PRINTF("\n请将UART0与PC串口进行连接,然后启动超级终端程序(115200, 8, N, 1)\n");

         PRINTF("\n从现在开始您从超级中断发送的字符将被回显在超级终端上\n");

                  char ch;

         char *st;

         char *st1;

         ch = Uart_Getch();

         Uart_SendByte(ch);

         st1 = st;

         *st++ = ch;

    /* 开始回环测试 */

         while (ch != '\r')

         {

                  // TODO

                  *st++ = ch;

                  showChar(ch);

                  ch = Uart_Getch();

                  Uart_SendByte(ch);

                  // 串口回环测试

         }

         Uart_SendString(st1);

         /*

         while (1)

         {

                  showString(st1);

         }

         */

         //显示字符串

         /*

         char *st;

         Uart_GetString(st);

         Uart_SendString(st);

         */

}

void showChar(char ch)

{

         unsigned char segtable[16] =

    {

    /* 0       1       2       3       4       5       6      7*/

    0xc0,   0xf9,   0xa4,   0xb0,   0x99,   0x92,   0x82,   0xf8,

    /* 8       9      A        B       C       D       E      F*/

    0x80,   0x90,   0x88,   0x83,   0xc6,   0xa1,   0x86,   0x8e,

         };

        

         *((unsigned char *)0x20007000) = 0x3b;

         if ((ch >= '0')&(ch <= '9'))

         {

                  *((unsigned char*)0x20006000) = segtable[ch - '0'];

                  Delay(1);

         }

         else if ((ch >= 'A')&(ch <= 'F'))

         {

                  *((unsigned char*)0x20006000) = segtable[ch - 'A' + 10];

                  Delay(1);

         }

         else

         {

                  *((unsigned char*)0x20006000) = 0x00;

         }

}

void showString(char *str)

{

         char *show = str;

         unsigned char segtable[16] =

    {

    /* 0       1       2       3       4       5       6      7*/

    0xc0,   0xf9,   0xa4,   0xb0,   0x99,   0x92,   0x82,   0xf8,

    /* 8       9      A        B       C       D       E      F*/

    0x80,   0x90,   0x88,   0x83,   0xc6,   0xa1,   0x86,   0x8e,

         };

         int i = 0;

         int j;

         while (*show != '\r')

         {

                  for (j = 0; j < 1000;j++)

                  {

                           *((unsigned char*)0x20007000) = ~(1 << i) & 0x3f;

                           if ((*show >= '0')&(*show <= '9'))

                           {

                                    *((unsigned char*)0x20006000) = segtable[*show - '0'];

                                    Delay(1);

                           }

                           else if ((*show >= 'A')&(*show <= 'F'))

                           {

                                    *((unsigned char*)0x20006000) = segtable[*show - 'A' + 10];

                                    Delay(1);

                           }

                           else

                           {

                                    *((unsigned char*)0x20006000) = 0x00;

                           }

                           show++;

                           i++;

                           i %= 6;

                  }

         }

}

五.结果及分析

1.运行程序,在键盘上输入的字符显示在超级终端和数码管上。

2.运行程序,数码管显示一串字符。

分析:语句

ch=Uart_Getch();

Uart_SendByte(ch);

即用来接收终端输入字符并传送。将其显示到数码管上则需要将其进行筛选,满足要求即可输出。而对于显示一串字符,则用到以下语句来获取字符串的值:

Uart_GetString(&a);

Uart_SendString(&a);

接着在0—F之间比较输出。

六.实验总结

1.三个实验不能同时运行,否则机器复位。

实验十 LCD显示实验

一.实验目的

1.了解LCD显示图形的方法。

2.了解LCD显示字符的方法(本次实验显示汉字)。

二.实验原理

         LCD显示器是通过给不同的液晶单元供电,控制其光线的通过与否,从而达到显示的目的。因此,LCD的驱动控制归于对每个液晶单元通断电的控制,每个液晶单元都对应着一个电极,对其通电,便可使用光线通过(也有刚好相反的,即不通电时光线通过,通电时光线不通过)。

         光源的提供方式有两种:透射式和反射式。笔记本电脑的LCD显示屏即为透射式,屏后面有一个光源,因此外界环境可以不需要光源。而一般微控制器上使用的LCD为反射式,需要外界提供光源,靠反射光来工作。

         LCD的驱动控制——扫描器控制方式:一般带有驱动模块的LCD显示屏使用总线驱动方式,这种LCD可以方便地与各种低档单片机进行接口,如8051系列单片机。由于LCD已经带有驱动硬件电路,因此模块给出的是总线接口,便于与单片机的总线进行接口。驱动模块具有八位数据总线,外加一些电源接口和控制信号。而且还自带显示缓存,只需要将要显示的内容送到显示缓存中就可以实现内容的显示。由于只有八条数据线,因此常常通过引脚信号来实现地址与数据线复用,以达到把相应数据送到相应显示缓存的目的。

三.实验内容及步骤

1.学习例程,在LCD上显示图形。

2.在LCD上显示汉字。如:显示“西安电子科技大学”等。

3.自行开发。

步骤:

1)新建一个工程,添加相应的文件,并修改相应的工程设置;

2)创建dispgraph.c文件,将该文件加入到工程中;

3)编辑dispgraph.c文件,添加Main函数,并在其中执行lcd_init操作;

4)编程 ;

5)编译下载、运行、调试、查看结果。

四.实验程序

/* 包含文件 */

#include "def.h"

#include "2410lib.h"

#include "option.h"

#include "2410addr.h"

#include "interrupt.h"

#include "lcdlib.h"

//#define STN_LCD

#define TFT_8_0

void (*PutPixel)(U32,U32,U32);

void Lcd_Disp_Char(void);

void Lcd_Disp_Grap(void);

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

// Function name     : Main

// Description      : JXARM9-2410 LCD显示实验主程序

//                    实现功能:

// Return type          : void

// Argument         : void

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

void Main(void)

{

         /* 配置系统时钟 */

    ChangeClockDivider(2,1);

    U32 mpll_val = 0 ;

    mpll_val = (92<<12)|(1<<4)|(1);

    ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);

   

    /* 初始化端口 */

    Port_Init();

   

    /* 初始化串口 */

    Uart_Init(0,115200);

    Uart_Select(0);

   

    /* 打印提示信息 */

         PRINTF("\n---LCD测试程序---\n");

         PRINTF("\n请将UART0与PC串口进行连接,然后启动超级终端程序(115200, 8, N, 1)\n");

         /* LCD初始化 */

    Lcd_Port_Init();

#ifdef STN_LCD

    Lcd_Init(MODE_CSTN_8BIT);

    Glib_Init(MODE_CSTN_8BIT);

    Lcd_CstnOnOff(1);

   

    Glib_ClearScr(0xff, MODE_CSTN_8BIT);

#else

         #ifdef TFT_8_0

                  rGPCCON &= ~(3<<8);

                  rGPCCON |= (2<<8);

             Lcd_Init(MODE_TFT_16BIT_640480);

             Glib_Init(MODE_TFT_16BIT_640480);

        

             Glib_ClearScr(0xffff, MODE_TFT_16BIT_640480);

             Lcd_PowerEnable(0, 1);

             Lcd_EnvidOnOff(1);       

         #else

             Lcd_Init(MODE_TFT_16BIT_240320);

             Glib_Init(MODE_TFT_16BIT_240320);

            

             Glib_ClearScr(0xffff, MODE_TFT_16BIT_240320);

             Lcd_PowerEnable(0, 1);

             Lcd_EnvidOnOff(1);

    #endif

#endif

    while(1)

    {

#define LCD_DISP_CHAR        

//#ifdef  LCD_DISP_CHAR    

         Lcd_Disp_Char();

//#else

         //Lcd_Disp_Grap();

//#endif

int i,j;

 for(j=100;j<500;j++)

         for(i=100;i<500;i++)

Glib_FilledRectangle(i,j,i+50,j+100,0xf800);

    }

}   

void Lcd_Disp_Char(void)

{

         /* 显示字符串 */

        Glib_disp_hzk16(30,400,"西安电子科技大学", 0x0);

        Delay(100);

         return;

}

void Lcd_Disp_Grap(void)

{

         int i,j;

        

    for(j=0;j<480;j++)

         for(i=0;i<640;i++) //RRRGGGBB

             (*PutPixel)(i,j,0xf800);

            

         Delay (10);      

  

    for(j=0;j<480;j++)

         for(i=0;i<640;i++) //RRRGGGBB

             (*PutPixel)(i,j,0x07e0);

  

         Delay (10);      

    for(j=0;j<480;j++)

         for(i=0;i<640;i++) //RRRGGGBB

             (*PutPixel)(i,j,0x001f);

  

         Delay (10);      

    for(j=0;j<480;j++)

         for(i=0;i<640;i++) //RRRGGGBB

             (*PutPixel)(i,j,0xffff);

  

         Delay (10);      

         /*int i,j;

         PRINTF("\ndis 1\n");

         for(i=0;i<640;i++)

             for(j=0;j<480;j++)

                      _PutTft16Bit_640480(i,j,*(short *)(0xf100 + (j*640 + i) * 2));*/

}

五.结果及分析

运行程序,屏幕上出现交替的图像,并同时显示字符。

六.实验总结

    汉字不能输入太长,否则会出现乱码。

相关推荐