单片机上机实验报告

姓名:

班级:

学号:

实验一  数码管实验

一、实验目的

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

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

二、实验仪器

      JXARM9-2440教学实验箱、ADT1000仿真器和ADT IDE集成开发环境、PC机。

三、实验原理

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

LED显示器的接口一般有静态显示与动态显示接口两种方式。

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

四、实验内容及步骤

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

1) 参照模板工程led(modules\led\led.apj),新建一个工程led,添加相应的文件,并修改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[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,

};

void Delay(int time);

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

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

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

/* 返回代码: 无                                                             */

/* 参数说明: 无                                                             */

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

void Test_Seg7(void) {   

       int i;     

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

       for(; ;)

       {

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

        {

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

        Delay (10000);

         }

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

        {

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

        Delay (10000);

        }

       }

      

       // TODO

}

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

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

/* Description : 循环 'time' 次                                             */

/* Return type :void                                                       */

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

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

void Delay(int time) {

    int i;

       int delayLoopCount=10000;

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

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

}

void Test_Seg7(void) {   

       int i;     

      

       for(; ;)

       {

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

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

         Delay (10000);

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

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

         Delay (10000);

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

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

         Delay (10000);

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

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

         Delay (10000);

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

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

         Delay (10000);

        }

      

      

       // TODO

}

六、结果及分析

我们了解了数码管的显示原理,基本掌握了JXARM9-2440 中数码管显示编程方法,用数码管显示出了,字母和数字。

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

一、实验目的

1、学习键盘驱动原理;

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

二、实验仪器

JXARM9-2440教学实验箱、ADT1000仿真器和ADT IDE集成开发环境、PC机、

串口连接线。

三、实验原理

键盘实现方案:

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

采用软件实现键盘扫描

软键盘实现方案:

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

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

JXARM9-2440的键盘模块

四、实验内容及步骤

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

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

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

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

步骤:

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

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

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

4) 编译key;

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

五、实验程序。

Keyboard.c

#include <string.h>

#include "2410addr.h"

#include "2410lib.h"

#include "timer.h"

#include "interrupt.h"

#define RECV_CMD_MAX_BUF 2048

char recv_buf[RECV_CMD_MAX_BUF];

int  recv_read = 0;

int  recv_write = 0;

char key_recv_buf[RECV_CMD_MAX_BUF];

int  key_recv_read = 0;

int  key_recv_write = 0;

// 键盘扫描

int  timer1_count = 0;

enum KEYBOARD_SCAN_STATUS

{KEYBOARD_SCAN_FIRST,

KEYBOARD_SCAN_SECOND,

KEYBOARD_SCAN_THIRD,

KEYBOARD_SCAN_FOURTH

};

int row = 0;

extern unsigned char output_0x10000000;

unsigned char    ascii_key, input_key[4], input_key1[4], key_mask = 0x0F;

unsigned char*   keyboard_port_scan = (unsigned char*)0x2000C000;

unsigned char*   keyboard_port_value = (unsigned char*)0x2000C000;

int              keyboard_scan_status[4] = {

                                                                                                  KEYBOARD_SCAN_FIRST,

                                                                                                  KEYBOARD_SCAN_FIRST,

                                                                                                  KEYBOARD_SCAN_FIRST,

                                                                                                  KEYBOARD_SCAN_FIRST

                                                                                             };

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;}

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

// Function name       : recv_key

// Description          : 将获取的键值加入按键缓冲区

// Return type            : void

// Argument         : int key

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

void recv_key(int key)

{key_recv_buf[key_recv_write] = key;

       key_recv_write ++;

       if(key_recv_write >= RECV_CMD_MAX_BUF)

              key_recv_write = 0;  

       if(key_recv_write == key_recv_read)

       {// 缓冲区以满

              key_recv_read ++;

              if(key_recv_read >= RECV_CMD_MAX_BUF)

                     key_recv_read = 0;

       }

}

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

// Function name       : Kbd_Scan

// Description          : 定时器1中断服务程序,用于扫描键盘,每隔10ms一次中断

// Return type            : void

// Argument         : void

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

void Kbd_Scan(void)

{int loopcnt = row, bexit = 0;

       int temp;

       // 键盘扫描

       for( loopcnt = row; loopcnt < row + 4; loopcnt ++)

       {if(loopcnt >= 4)

                     temp = loopcnt - 4;

              else

                     temp = loopcnt;

              switch(keyboard_scan_status[temp])

              {case KEYBOARD_SCAN_FIRST:

                            *keyboard_port_scan = output_0x10000000 & (~(0x00000001<<temp));        /*将row列置低电平 */

                            keyboard_scan_status[temp] = KEYBOARD_SCAN_SECOND;

                            bexit = 1;

                            break;

                     case KEYBOARD_SCAN_SECOND:

                            input_key[temp] = (*keyboard_port_value) & key_mask; /*并获取第一次扫描值*/

                            if(input_key[temp] == key_mask)  

                                   keyboard_scan_status[temp] = KEYBOARD_SCAN_FIRST;       /* 没有按键,回到开始状态                 */

                            else

                            {      keyboard_scan_status[temp] = KEYBOARD_SCAN_THIRD;             /* 有按键           */

                     bexit = 1;

                            }

                            break;

                     case KEYBOARD_SCAN_THIRD:

                            if (((*keyboard_port_value) & key_mask) != input_key[temp])

                                   keyboard_scan_status[temp] = KEYBOARD_SCAN_FIRST;

                            else

                            {

                                   ascii_key = key_get_char(temp, input_key[temp]);

                                   keyboard_scan_status[temp] = KEYBOARD_SCAN_FOURTH;

                                  

                                   *keyboard_port_scan = output_0x10000000 & (~(0x00000001<<temp));        /*将row列置低电平 */

                                   bexit = 1;

                            }

                            break;

                     case KEYBOARD_SCAN_FOURTH:

                            input_key1[temp] = (*keyboard_port_value) & key_mask;     /*并获取第一次扫描值*/

                            if(input_key1[temp] == key_mask)

                            {

                                   // get a key

                                   recv_key(ascii_key);                              

                                   keyboard_scan_status[temp] = KEYBOARD_SCAN_FIRST;

                            }else

                            {

                                   *keyboard_port_scan = output_0x10000000 & (~(0x00000001<<temp));        /*将row列置低电平 */

                                   bexit = 1;      }

                            break;}                

              if(bexit)

                     break;}

       row = temp; }

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

// Function name       : Key_GetKey

// Description          : 如果有键按下返回键,否则返回0

// Return type            : char

// Argument         :

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

char Key_GetKey()

{      char ch;

       if(key_recv_write == key_recv_read)

       {/* no key found */

              ch = 0;}else

       {      ch = key_recv_buf[key_recv_read];

              key_recv_read ++;

              if(key_recv_read >= RECV_CMD_MAX_BUF)

                     key_recv_read = 0;}

       return ch;

}

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

// Function name       : Key_GetKeyPoll(查询方式)

// Description          : 如果有键按下返回键,否则返回0

// Return type            : char

// Argument         :

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

char Key_GetKeyPoll()

{      int row;

       unsigned char    ascii_key, input_key, input_key1, key_mask = 0x0F;

       for( row = 0; row < 4; row++)

       {*keyboard_port_scan = output_0x10000000 & (~(0x00000001<<row));        /*将row列置低电平       */

              Delay(3);                                                       /*延时                        */

              input_key = (*keyboard_port_value) & key_mask;    /*并获取第一次扫描值*/

              if(input_key == key_mask)       continue;             /* 没有按键                     */

                                  

              /* 延时,再次获取扫描值,如果两次的值不等,则认为是一个干扰         */

              Delay(3);

              if (((*keyboard_port_value) & key_mask) != input_key) continue;

                    

              // 等待按键松开

              while(1)

              {

                     *keyboard_port_scan = output_0x10000000 & (~(0x00000001<<row));        /*将row列置低电平  */

                     Delay(3);

                     input_key1 = (*keyboard_port_value) & key_mask;  /*并获取第一次扫描值*/

                           

                     if(input_key1 == key_mask)     break;           /* 没有按键                     */}

              ascii_key = key_get_char(row, input_key);   /* 查表                      */   

              return ascii_key;                             /* 显示结果                     */}

return 0;}

六、结果及分析。

成功将键盘输入与要求的图上对应。

                  实验三  中断实验

一、实验目的

   1、了解中断的作用;

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

   3、掌握ARM中断编程。

二、实验仪器

JXARM9-2440教学实验箱、ADT1000仿真器和ADT IDE集成开发环境、PC机。

三、实验原理

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

四、实验内容及步骤

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

(二)编写中断处理程序,处理外部中断23,控制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) 编译、下载并运行程序烁。

五、实验程序

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

/* 包含文件 */

#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_Enable(IRQ_EINT2);

   

    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;

      

              /*8个灯亮灭*/

       unsigned char output_0x10000000 = 0xff;

       while(1)

       {

              output_0x10000000 = 0xff;

              *((unsigned char *)0x20005000) = output_0x10000000;

              delay();

              output_0x10000000 = 0x00;

              *((unsigned char *)0x20005000) = output_0x10000000;

              delay();

       }

       }

}

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

// 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;

      

      

/*8个依次亮灭*/

      

       unsigned char output_0x10000000 = 0xff;

       while(1)

       {      int i;

              output_0x10000000 = 0x01;

              *((unsigned char *)0x20005000) = output_0x10000000;

              delay();

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

                    

              {

                    

                     output_0x10000000 = output_0x10000000<<1;

                     *((unsigned char *)0x20005000) = output_0x10000000;

                     delay();

              }

             

       }

}

}

void delay()

{

       int index = 0;

      

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

}

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

只需将中断请求和使能中断的端口改为EINT3,即可调用中断三,其余程序不变

/* 请求中断 */

       Irq_Request(IRQ_EINT3, eint3_isr);

    /* 使能中断 */

    Irq_Enable(IRQ_EINT3);

   

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

只需任选一个中断(以中断三为例),将中断处理程序的内容改为数码管显示即可。

#define U8 unsigned char

unsigned char seg8table[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       : eint3_isr

// Description          : EINT3中断处理程序

// Return type            : int

// Argument         : void

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

void eint3_isr(void)

{

       Irq_Clear(IRQ_EINT3);       

    if(dither_count3 > 10)

    {

          dither_count3 = 0;

/*数码管*/

   int i;

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

    for(;;)

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

      {*((U8*) 0x20006000)=seg8table[i];

         Delay(100);

       }

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

      {  *((U8*) 0x20006000)=seg8table[i];

            Delay(100);

       }

    }

}

}

void delay()

{

       int index = 0;

      

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

}

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

/* Function name : 循环延时子程序                                           /* Description : 循环 'time' 次                                             /* Return type :void                                                       /* Argument      : 循环延时计数器                                           */

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

void Delay(int time) {

    int i;

       int delayLoopCount=1000;

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

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

}

六、结果及分析

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

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

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

七、实验总结

通过对中断的合理处理,这样CPU就避免了把大量时间耗费在等待、查询状态信号的操作上,使其工作效率得以大大地提高。

实验四  A/D实验

一、实验目的

   1、了解模数转换的基本原理;

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

二、实验仪器

JXARM9-2440教学实验箱、ADT1000仿真器和ADT IDE集成开发环境、PC机、串口连接线。

三、实验原理

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

采样:

按采样定理对模拟信号进行等时间间隔采样,将得到的一系列时域上的样值去代替u=f(t),即用u0、u1、…un代替u=f(t)。

这些样值在时间上是离散的值,但在幅度上仍然是连续模拟量。

 

                        

量化:

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

             u0=2.4Q 2Q

             u1=4.0Q 4Q

             u2=5.2Q 5Q

             u3=5.8Q 5Q

编码:

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

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

   

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

四、实验内容及步骤

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

(二)

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

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

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"

#define U8 unsigned char

unsigned char seg7table1[16] = {

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

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

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

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

};

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

// 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

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

//==================================================================================

void Test_Adc(void)

{

    int i;

    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)

    {

                            // TODO

        a0= Adc_Get_Data( 0, 2500000);

        a1= Adc_Get_Data(1, 2500000);

         float  b,A0;

           int c;

          int a[6];

          

           b=a0*3.3/(1024);

           A0=b;

           b=b*100000;

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

           {

               c=(int)b%10;

               a[i]=c;

               b=b/10;

            }

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

                       *((U8*) 0x20006000)=seg7table1[a[0]];

                       Delay1(1);

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

          *((U8*) 0x20006000)=seg7table1[a[1]];

          Delay1(1);

     

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

                *((U8*) 0x20006000)=seg7table1[a[2]];

                Delay1(1);

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

           *((U8*) 0x20006000)=seg7table1[a[3]];

          Delay1(1);

                     

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

          *((U8*) 0x20006000)=seg7table1[a[4]];

                Delay1(1);

                 

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

                       *((U8*) 0x20006000)=seg7table1[a[5]]&0x7f;

                                   Delay(1);

    PRINTF("\rAIN0: %04d AIN1: %04d", a0,a1);

                 PRINTF("\rvoltage-->AIN0: %05f", A0);

    }

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

                   PRINTF("\n");

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

}

void Delay1(int time) {

    int i;

             int delayLoopCount=1000;

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

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

}

五、结果分析:

通过对模拟AD的变化结构在串口和LED上显示。

六、实验总结:

    通过AD转化实验,可以有效地对一下变量进行采集,分析和处理

实验五 S3C2440A的实时时钟

一、实验目的

了解实时时钟在嵌入式系统中的作用;

掌握实时时钟的使用。

二、实验原理

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

三、实验内容及步骤

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

(二)

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

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

        3、自行开发。

步骤:

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

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

根据内容编程。编译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;

/* 全局变量 */

int led_index = 0;

int ext0_count = 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);  

}

void delay(int time) {

    int i;

       int delayLoopCount=1000;

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

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

}

unsigned char seg70table[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 实时时钟实验主程序

//                    完成功能:

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

//                        设置当前日期、时间

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

//                        时间告警功能:每分钟的第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 */

       // TODO

       m_date.year=0x2015;

       m_date.mon=0x05;

       m_date.day=0x07;

       m_date.week_day=0x03;

       m_date.hour=0x18;

       m_date.min=0x12;

       m_date.sec=0x02;

      

   

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

    rtc_set_date(&m_date);

   

    m_date.sec        =    0x05 ;

   

       // TODO

       rtc_alarm_set(&m_date,0x41);

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

      

       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;

                   

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

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

                 delay(10);

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

             *((unsigned char*) 0x20006000)=seg70table[m_date.hour/16];

             delay(10);

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

             *((unsigned char*) 0x20006000)=seg70table[m_date.hour%16];

             delay(10); 

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

             *((unsigned char*) 0x20006000)=seg70table[m_date.min/16];

             delay(10); 

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

             *((unsigned char*) 0x20006000)=seg70table[m_date.min%16];

             delay(10); 

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

             *((unsigned char*) 0x20006000)=seg70table[m_date.sec/16];

             delay(10); 

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

             *((unsigned char*) 0x20006000)=seg70table[m_date.sec%16];

             delay(10); 

             if(m_date.sec%16==0){

                    *((unsigned char*) 0x20005000)=0xff;

                    delay(1000);

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

                    delay(1000);

             }

             

       }

       

    };

}

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

// 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                  ");

}

五、结果及分析

面板晶体管由于个数的限制只能显示时分秒,

六、实验总结

采用S3C2440A中提供的RTC时间节拍中断,让它在规定时间中断一次,每次中断读取时间,刷新一次实时时钟,实现RTC的实时控制。并通过应用程序的编写充分利用S3C2440A芯片实时时钟单元资源,提高整个系统的性能,为在需要时钟作为参考的工作环境提供了便利。

实验六PWM实验

一、实验目的

Ø   1、了解PWM的基本原理;

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

二、实验仪器

Ø      JXARM9-2440教学实验箱、ADT1000仿真器和ADT IDE集成开发环境、PC机。

三、实验原理

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

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

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

Ø   

四、实验内容及步骤

Ø  (一)学习与分析例程;

Ø  (二)

Ø  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"

/* 函数声明 */

voidtest_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

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

voidtest_pwm()

{

       rTCFG0 = 0xff;

       rTCFG1 = 0x1;

       int N;

       /*输出脉冲:频率8000Hz, 2/3占空比 */

       N = PCLK / 256 / 4 / 8000;

       rTCNTB0 = N;

       rTCMPB0 = 2 * N / 3;

       rTCON = 0x9;

       Delay(100);

intfeq;

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

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

       {

              N = PCLK / 256 / 4 / feq;

              rTCNTB0 = N;

              rTCMPB0 = 2 * N / 3;

              rTCON = 0xa;

              rTCON = 0x9;

              Delay(100);

              rTCON = 0x0;

       }

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

      

       N = PCLK / 256 / 4 / 1000;

       rTCNTB0 = N;

       inti;

       int N1;

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

       {

              N1 = i*N / 100;

              rTCMPB0 = N1;

              rTCON = 0xa;

              rTCON = 0x9;

              Delay(100);

              rTCON = 0x0;

       }

       int  song[32]={ 659,659,698,784,784,698,659,578,523523578,659,659,578,578,659,659,698,784,784,698,659,578,523523,578,659,578,

523,523 };

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

       {

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

       rTCNTB0=N;

       rTCMPB0=2*N/3;

       rTCON=0xa;

       rTCON=0x9;

      

Delay(50);

rTCON=0x0;

 }

       // TODO

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

      

      

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

      

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

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

}

七、结果及分析。

了解到了pwm的原理及应用,以及简单的编程方法。

实验七  看门狗实验

一、实验目的

 1、了解WATCHDOG的作用;

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

二S3C2440A的看门狗定时器有两个特征:

1.  可做常规定时器使用,并且可以产生中断;

2.  作为看门狗使用,当计数值减为0时,内部复位信号被激活。

三、实验内容及步骤

(一)学习与分析例程;

(二)

         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;

/* 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+0x04 ;

    m_date.mon             =    0x03 ;

    m_date.day        =    0x02 ;

    m_date.week_day     =    0x02 ;

    m_date.hour             =    0x15 ;

    m_date.min       =    0x40 ;

    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);

      

       // TODO

       /* 打开看门狗复位功能 */

       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

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

int numm=1;

void rtc_tick_isr(void)

{

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

       *((U8*) 0x10000006) = 0x00;

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

  

   led_index++;

  

       // TODO

   /* 喂狗 */

  

      //    rWTCNT = 8448 *2;

         //    PRINTF("喂狗\n\n");

  

  

     if(numm==3){

         rWTCNT = 8448 *2;

             PRINTF("喂狗失败\n\n");

         numm=0;

   }

     numm++; 

}

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

// 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                  ");

}

五、实验总结

  通过这次实验进一步了解看门狗的工作原理和功能,以及看门狗寄存器定时周期的计算方法。

  在实验过程中遇到了很多问题,如:无法连接到超级终端,运行设备,USB驱动无法正确装载等等,要通过反反复复的操作。

实验八 串口通讯实验

一、实验目的

1、掌握ARM的串行口工作原理;

2、学习编程实现ARM的UART通讯;

3、掌握S3C2440寄存器配置方法

二、实验仪器

JXARM9-2440教学实验箱、ADT1000仿真器和ADT IDE集成开发环境、串口连接线、PC机

三、UART简介

UART(Universal Asynchronous Receiver and Transmitter,通用异步收发器),采用异步串行通信方式。

UART以字符为单位进行数据传输,每个字符的传输格式如图所示,包括线路空闲状态(高电平)、起始位(低电平)、5~8位数据位、校验位(可选)和停止位(位数可以是1、1.5或2位)。

UART方框图(带FIFO)

四、UART操作

UART的操作包括了数据发送、数据接收、中断发生、波特率发生、环回(Loopback)模式、红外模式和自动流控制。

数据发送:

发送的数据帧是可编程的。它包括1个起始位、5~8个数据位、1个可选的奇偶校验位和1~2个停止位,具体设置由行控制寄存器(ULCONn)确定。发送器还可以产生终止信号,强制在一帧发送期间连续输出“0”

数据接收:

与数据发送类似,接收的数据帧也是可编程的。它包括1个起始位,5~8个数据位、1个可选的奇偶校验位和1~2个停止位,具体设置由行控制寄存器(ULCONn)确定。接收器能够检测出溢出(overrun)错误、奇偶校验错误、帧错误和终止情况,每个都可以设置一个错误标志。

中断/DMA请求产生(Interrupt/DMA Request Generation

S3C2440A的每个UART有7个状态(Tx/Rx/Error)信号:溢出错误、奇偶校验错误、帧错误、终止、接收缓冲数据准备好、发送缓冲空和发送移位器空。这些状态通过相关的状态寄存器(UTRSTATn/UERSTATn)指示。

如果接收错误中断请求使能位在控制寄存器UCONn中设置为1,则每个都可以引起接收错误中断请求。

如果控制寄存器(UCONn)中的接收模式置为“1”(中断请求模式或查询模式),当接收状态满足一定的条件,将产生Rx中断。

如果控制寄存器(UCONn)中的发送模式置为1(中断请求模式或查询模式),当发送状态满足一定的条件,将产生Tx中断。

UART错误状态FIFO

错误状态FIFO指示出FIFO寄存器之中的数据错误接收。

错误中断将只在数据包含错误并准备读出时发出。为了清除错误状态FIFO,带错误的URXHn和UERSTATn必须被读取出来。

例如,假定UART Rx FIFO顺序接收A、B、C、D和E字符,在接收“B”时发生了帧错误,并且在接收“D”时发生了奇偶校验错误。

实际上,因为不读取接收带错误字符,UART接收错误并不会产生任何错误中断,一旦读取字符将引发错误中断。

UART专用功能寄存器

UART线路控制寄存器:ULCON0、ULCON1、ULCON2

UART控制寄存器:UCON0、UCON1、UCON2

UART FIFO 控制寄存器:UFCON0、UFCON1、UFCON2

UART MODEM控制寄存器:UMCON0、UMCON1

UART TX/RX 状态寄存器:UTRSTAT0,UTRSTAT1、UTRSTAT2

UART错误状态寄存器:UERSTAT0,UERSTAT1、UERSTAT2

UART FIFO 状态寄存器:UFSTAT0、UFSTAT1 、UFSTAT2

UART MODEM状态寄存器:UMSTAT0、UMSTAT1

UART发送缓冲寄存器:UTXH0、UTXH1、UTXH2

UART接收缓冲寄存器:URXH0,URXH1 、URXH2

UART波特率分频寄存器:UBRDIV0,UBRDIV1、UBRDIV2

五、实验内容及步骤

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

(二)

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

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

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

六、实验程序

/* 包含文件 */

#include "def.h"

#include "2410lib.h"

#include "option.h"

#include "2410addr.h"

#include "interrupt.h"

void delay( int count )

{

       int cnt;

      

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

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

}

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

// Function name       : Main

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

//                    实现功能:

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

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

// Return type            : void

// Argument         : void

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

#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,

    };

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");

      

              int led0,led1,led2,led3,led4,led5,i;

              char str[20]={0};

              Uart_GetString(str);

              PRINTF("\n---超级终端发送字符串了哈哈---\n");

              Uart_SendString(str);

              PRINTF("\n");

              delay(500);

             

    /* 开始回环测试 */

       while(1)

       {

              // TODO

              // 串口回环测试

              led0=str[0]-'a';

              led1=str[1]-'a';

              led2=str[2]-'a';

              led3=str[3]-'a';

              led4=str[4]-'a';

              led5=str[5]-'a';

      

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

                *((u8*)0x20006000)=segtable[led0+10];

             delay(5); 

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

                *((u8*)0x20006000)=segtable[led1+10];

             delay(5); 

      

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

                *((u8*)0x20006000)=segtable[led2+10];

             delay(5); 

      

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

                *((u8*)0x20006000)=segtable[led3+10];

             delay(5); 

      

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

                *((u8*)0x20006000)=segtable[led4+10];

             delay(5); 

      

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

                *((u8*)0x20006000)=segtable[led5+10];

             delay(5); 

             

       }

}

七、实验总结

本实验主要是让我们了解七段数码管的表示,运用单片机控制不同的数字显示。

实验九步进电机实验

一、实验目的

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

二、实验仪器

Ø    JXARM9-2440教学实验箱、ADT1000仿真器和ADT IDE集成开发环境、PC机。

三、实验原理

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

Ø  脉冲分配信号:

Ø  整步模式脉冲分配

Ø  四、实验内容及步骤

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

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

Ø  步骤:

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

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

Ø  3)编写程序;

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

五、参考程序

//ioport unsigned port100e;

/* functions */

void delay(int count);

#define U8 unsigned char

unsigned char zheng[4] = {

   0x09,0x0a,0x06,0x05

};

unsigned char fangai[4] = {

   0x05,0x06,0x0a,0x09

};

unsigned char ledzheng[8] = {

   0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80

};

unsigned char ledfan[8] = {

   0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01

};

// 整步模式正转脉冲

void Main(void)

{

       int row;

      

       for( ; ; )

       {

              // TODO

              for(row=0;row<80;row++){

                     (*(U8*)0x20002000)=zheng[row%4];

                     delay(50);

                     (*(U8*)0x20005000)=ledzheng[row%8];

                     delay(5);

              }

              delay(5000);

              for(row=0;row<80;row++){

                     (*(U8*)0x20002000)=fangai[row%4];

                     delay(50);

                     (*(U8*)0x20005000)=ledfan[row%8];

                     delay(5);

                     }

               delay(5000);

       }

      

      

             

             

      

}

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

// 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++);

}

五、结果及分析。

我们了解到了步进电机状态工作的的方式。

实验十 LCD显示实验

一、实验目的

1、了解LCD显示图形的方法;1

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

二、实验仪器

JXARM9-2440教学实验箱、ADT1000仿真器和ADT IDE集成开发环境、串口连接线、PC机

三、实验原理

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

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

LCD的驱动控制——扫描器控制方式:

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

嵌入式控制系统人机界面一般使用LCD(Liquid Crystal Display,液晶显示器的简称)做显示器件。人机界面设计基本上归结为两个问题,一是如何解决在液晶显示器上显示汉字和各种曲线,另一个就是各类液晶显示器件驱动问题。

四、实验内容及步骤

1、学习例程在LCD上显示图形;

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

3、自行开发

五、实验程序

/* 包含文件 */

#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);

voidLcd_Disp_Char(void);

voidLcd_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

inti,j;

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

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

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

    }

}   

voidLcd_Disp_Char(void)

{

       /* 显示字符串 */

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

       Delay(100);

       return;

}

voidLcd_Disp_Grap(void)

{

       inti,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);      

       /*inti,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));*/

}

六、实验总结

通过LED灯的实验让我们了解LED屏显示的原理,同时学会修改程序。

相关推荐