姓名:
班级:
学号:
实验一 数码管实验
一、实验目的
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就避免了把大量时间耗费在等待、查询状态信号的操作上,使其工作效率得以大大地提高。
四、实验内容及步骤
(一)学习例程,对其关键程序与设置进行分析。
(二)编写中断处理程序,处理外部中断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) 编译、下载并运行程序烁。
五、实验程序
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屏显示的原理,同时学会修改程序。
单片机实验报告学生姓名学号专业指导教师学院信息与电气工程学院20xx年11月单片机实验报告实验一MCS51指令系统实验数据排序1实…
通信与信息工程学院20xx20xx学年第二学期实验报告课程名称单片机原理及应用专业班级学号学生姓名指导教师日期20xx年4月15日…
题目单片机组成原理实验报告学院计算机科学与工程学院专业信息安全姓名学号20xx年12月8日实验一输入输出接口编程一实验目的1掌握K…
51单片机课程设计报告学院:专业班级:姓名:指导教师:设计时间:51单片机课程设计一、设计任务与要求1.任务:制作并调试51单片机…
海南大学届单片机实验报告4份论文题目学生姓名学号所在院系专业班级授课教师完成时间蜂鸣器实验实验目的1熟悉实验板中蜂鸣器工作原理掌握…
单片机原理实验报告实验一熟悉μ’nSP?IDE集成开发环境下C语言程序的编写【实验目的】1.熟悉μ’nSP?IDE集成开发环境的使…
PIC单片机技术上机实验报告实验项目:定时/计数姓名:专业:班级:学号:学期:1314学年2学期20xx一、实验名称×××二、实验…
实验一数码管实验一实验目的1了解数码管的显示原理2掌握JXARM92440中数码管显示编程方法二实验原理7段LED由7个发光二极管…
项目一万年历班级学号姓名一任务目的通过对万年历的设计和制作应用了单片机的数码管键盘接口技术以及定时计数器中断等程序设计技术进一步训…
广西科技大学筹课程设计说明书课题名称单片机电子时钟的设计系别职业技术教育学院专业电子信息工程班级学号姓名报告样板指导教师I摘要单片…
题目单片机组成原理实验报告学院计算机科学与工程学院专业信息安全姓名学号20xx年12月8日实验一输入输出接口编程一实验目的1掌握K…