实验一 数码管实验
一.实验目的
1.了解数码管的显示原理;
2.掌握JXARM9-2440 中数码管显示编程方法。
二.实验原理
7段LED由7个发光二极管按“日”字形排列,所有发光二极管的阳极连在一起称共阳极接法,阴极连在一起称为共阴极接法。
LED显示器的接口一般有静态显示与动态显示接口两种方式。本实验中采用的是动态显示接口,其中数码管扫描控制地址为0x20007000,位0-位5每位分别对应一个数码管,将其中某位清0 来选择相应的数码管,地址0x20006000 为数码管的数据寄存器。数码管采用共阳方式,向该地址写一个数据就可以控制LED 的显示,其原理图如图所示。
三.实验内容及步骤
1、六个数码管同时正向显示0-F ,然后反向显示F-0。
1) 参照模板工程leddemo(modules\leddemo\leddemo.apj),添加相应的文件,并修改led 的工程设置;
2) 创建led.c 并加入到工程led 中;
3) 编写LED 显示函数void led_display(void),正向显示0-F 然后反向显示F-0,并循环执行以上动作,在每次显示之间延时一段时间;
4) 编译led,成功后,下载并运行,观察结果。
2、在六个数码管上依次显示“HELLO”,可分辨出轮流显示。步骤同上。
3、在六个数码管上依次显示“HELLO”,分辨不出轮流显示。步骤同上。
4、在每个数码管上递增显示0-9 。步骤同上。
四.实验程序
/****************************************************************************/
/*文件名称: LEDSEG7.C */
/*实验现象: 数码管依次显示出0、1,2、……9、A、B、C、D、E、F */
/****************************************************************************/
#define U8 unsigned char
unsigned char seg7table[18] = {
/* 0 1 2 3 4 5 6 7*/
0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8,
/* 8 9 A B C D E F*/
0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e,
/*H L */
0x89, 0xc7,
};
void Delay(int time);
/****************************************************************************/
/* 函数说明: JXARM9-2410 7段构共阳数码管测试 */
/* 功能描述: 依次在7段数码管上显示0123456789ABCDEF */
/* 返回代码: 无 */
/* 参数说明: 无 */
/****************************************************************************/
void Test1_Seg7(void) //正向和反向显示
{
int i;
*((U8*)0x20007000)=0x0;
for( ; ; )
{
for(i=0;i<0x10;i++)
{
*((U8*)0x20006000)=seg7table[i];
Delay(9000);
}
for(i=0xf;i>=0;i--)
{
*((U8*)0x20006000)=seg7table[i];
Delay(9000);
}
}
}
void Test2_Seg7(void) //显示hello,更改Delay的数值,可得分辨出和分辨不出
{
int i;
for( ; ; )
{
*((U8*)0x20007000)=0x3e;
*((U8*)0x20006000)=seg7table[0];
Delay(1);
*((U8*)0x20007000)=0x3d;
*((U8*)0x20006000)=seg7table[17];
Delay(1);
*((U8*)0x20007000)=0x3b;
*((U8*)0x20006000)=seg7table[17];
Delay(1);
*((U8*)0x20007000)=0x37;
*((U8*)0x20006000)=seg7table[14];
Delay(1);
*((U8*)0x20007000)=0x2f;
*((U8*)0x20006000)=seg7table[16];
Delay(1);
}
}
unsigned char table[6]={0x3e,0x3d,0x3b,0x37,0x2f,0x1f}; //递增显示0~9
void Test3_Seg7(void)
{
int i,j;
for(;;)
{
for(j=0;j<6;j++)
{
*((U8*)0x20007000)=table[j];
for(i=0;i<0xa;i++)
{
*((U8*)0x20006000)=seg7table[i];
Delay(10000);
}
}
}
}
/****************************************************************************/
/* Function name : 循环延时子程序 */
/* Description : 循环 'time' 次 */
/* Return type :void */
/* Argument : 循环延时计数器 */
/****************************************************************************/
void Delay(int time) {
int i;
int delayLoopCount=1;
for(;time>0;time--);
for(i=0;i<delayLoopCount;i++);
}
五.结果及分析
1.六个数码管同时显示,从0——F,接着从F——0反向显示。
通过地址20007000选择哪个数码管亮,通过地址20006000决定数码管输出的内容。再通过循环可完成轮流显示。
2.可分辨出:从数码管的右边至左边依次显示hello
分辨不出:数码管上显示hello。
由于改变了Delay的数值,导致频率变化
3.每个数码管递增显示0——9。
原理同一,靠循环显示出0、1、2、3、4、5、6、7、8、9。
六.实验总结
1.由于数码管为共阳极,小数点为最高位,A为最低位,所以显示内容一定要计算正确。
2.循环条件要选择正确。
实验二 键盘输入与I/O实验
一.实验目的
1.学习键盘驱动原理;
2.掌握通过CPU的I/O扩展键盘的方法。
二.实验原理
1.键盘实现方案
(1)采用专门的芯片实现键盘扫描
(2)采用软件实现键盘扫描
2.软键盘实现方案
当开关打开时,通过处理器的I/O 口的一个上拉电阻提供逻辑1;当开关闭合时,处理器的I/O 口的输入将被拉低到逻辑0。
3.按键抖动
开关并不完善,因为当它们被按下或者被释放时,并不能够产生一个明确的1或者0。尽管触点可能看起来稳定而且很快地闭合,但与微处理器快速的运行速度相比,这种动作是比较慢的。当触点闭合时,其弹起就像一个球。弹起效果将产生如下图所示的好几个脉冲。弹起的持续时间通常将维持在5ms~30ms 之间。
4.矩阵键盘电路
(1)一个瞬时接触开关(按钮)放置在每一行与每一列的交叉点。每一行由一个输出端口的一位驱动,每一列由一个电阻器上拉且供给输入端口一位。
(2)键盘扫描过程就是让微处理器按有规律的时间间隔查看键盘矩阵,以确定是否有键被按下。
(3)一旦处理器判定有一个键按下,键盘扫描软件将过滤掉抖动并且判定哪个键被按下。
(4)每个键被分配一个称为扫描码的唯一标识符。应用程序利用该扫描码,根据按下的键来判定应该采取什么行动,换句话说,扫描码将告诉应用程序按下哪个键。
5.键盘扫描算法
(1)初始化:所有的行(输出端口)被强行设置为低电平。
(2)在没有任何键按下时,所有的列(输入端口)将读到高电平。
(3)任何键的闭合将造成其中的一列变为低电平。
(4)一旦检测到有键被按下,就需要找出是哪一个键。过程很简单,微处理器只需在其中一行上输出一个低电平。如果它在输入端口上发现一个0值,微处理器就知道在所选择行上产生了键的闭合。
6. JXARM9-2440的键盘模块
JXARM9-2440具有4×4的软键盘。原理图如下:
三.实验内容及步骤
(一)学习与分析例程中的各个程序以及主要函数,以进一步理解键盘的工作原理。
(二)获取按键值,在串口显示。
(三)使按键按照如图的顺序显示出来。
(四)将键盘按键值在数码管上显示。或自行开发。
步骤:
1) 参照模板工程key(modules\key\key.apj),新建一个工程key,添加相应的文件,并修改key 的工程设置;
2) 创建main.c 并加入到工程key 中;
3) 按照实验内容编写相应程序;
4) 编译key;
5) 下载程序并运行,按键看串口是否有显示;看数码管是否输出相应键值。
四.实验程序
#include "def.h"
#include "2410lib.h"
#include "option.h"
#include "2410addr.h"
#include "interrupt.h"
#define U8 unsigned char
unsigned char segtable[16] = {
/* 0 1 2 3 4 5 6 7*/
0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8,
/* 8 9 A B C D E F*/
0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e,
};
/********************************************************************
// Function name : Main
// Description : JXARM9-2410 键盘实验主程序
// 实现功能:
// Return type : void
// Argument : void
*********************************************************************/
void Main(void)
{
/* 配置系统时钟 */
ChangeClockDivider(2,1);
U32 mpll_val = 0 ;
mpll_val = (92<<12)|(1<<4)|(1);
ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);
/* 初始化端口 */
Port_Init();
/* 初始化串口 */
Uart_Init(0,115200);
Uart_Select(0);
/* 打印提示信息 */
PRINTF("\n---键盘测试程序---\n");
PRINTF("\n请将UART0与PC串口进行连接,然后启动超级终端程序(115200, 8, N, 1)\n");
/* 开始回环测试 */
while(1)
{
unsigned char ch;
int i;
ch=Key_GetKeyPoll();
if(ch != 0) //按键值在数码管上显示
{
PRINTF("\r'%c'键按下", ch);
*((U8*)0x20007000) = 0x3B;
if(ch>='9')
{
*((U8*)0x20006000)=segtable[(int)ch-0x41+10];
}
else
{
*((U8*)0x20006000)=segtable[(int)ch-0x30];
}
}
}
}
使按键如图所示显示,在keyboard.c中更改以下程序的数值便可达到效果
char key_get_char(int row, int col)
{
char key = 0;
switch( row )
{
case 0:
if((col & 0x01) == 0) key = 'F';
else if((col & 0x02) == 0) key = 'E';
else if((col & 0x04) == 0) key = 'D';
else if((col & 0x08) == 0) key = 'C';
break;
case 1:
if((col & 0x01) == 0) key = 'B';
else if((col & 0x02) == 0) key = '9';
else if((col & 0x04) == 0) key = '6';
else if((col & 0x08) == 0) key = '3';
break;
case 2:
if((col & 0x01) == 0) key = 'A';
else if((col & 0x02) == 0) key = '8';
else if((col & 0x04) == 0) key = '5';
else if((col & 0x08) == 0) key = '2';
break;
case 3:
if((col & 0x01) == 0) key = '0';
else if((col & 0x02) == 0) key = '7';
else if((col & 0x04) == 0) key = '4';
else if((col & 0x08) == 0) key = '1';
break;
default:
break;
}
return key;
}
五.结果及分析
1.任意按键,串口可显示出按键值;更改为如图所示后,依然显示正确。
加入了获取按键值的函数,可将按键值传输到串口。
2. 按键值可显示在数码管上
将获取的按键值转换成十六进制数进行显示。
六.实验总结
了解keyboard.c中按键排列顺序,字符转换十六进制数时要转换正确。
实验三 中断实验
一.实验目的
1.了解中断的作用;
2.掌握嵌入式系统中断的处理流程;
3.掌握ARM中断编程。
二.实验原理
1.当CPU进行主程序操作时,外设的数据已存入输入端口的数据寄存器;或端口的数据输出寄存器已空,由外设通过接口电路向CPU发出中断请求信号,CPU在满足一定的条件下,暂停执行当前正在执行的主程序,转入执行相应能够进行输入/输出操作的子程序,待输入/输出操作执行完毕之后CPU再返回并继续执行原来被中断的主程序。这样CPU就避免了把大量时间耗费在等待、查询状态信号的操作上,使其工作效率得以大大地提高。
三.实验内容及步骤
(一)学习例程,对其关键程序与设置进行分析。
(二)编写中断处理程序,处理外部中断2,3,控制LED灯闪烁或数码管显示。
1、当外部中断2发生时,使8个LED在亮灭间切换;
2、当外部中断3发生时,使8个LED等依次亮一下。
3、当中断发生时,控制数码管显示。
步骤:
1) 参照模板工程,新建一个工程interrupt,添加相应的文件,并修改interrupt 的工程设置;
2) 加入如下文件到interrupt 中:common\2440lib.c、;asm\2440init.s、asm\2440slib.s 和common\interrupt.c。
3) 根据实验内容编写外部中断2,3的中断处理程序,并保存为main.c 文件,将该文件加入到工程中;
4) 编译、下载并运行程序。
四.实验程序
#include "def.h"
#include "2410lib.h"
#include "option.h"
#include "2410addr.h"
#include "interrupt.h"
/* functions */
void eint2_isr(void) __attribute__ ((interrupt("IRQ")));;
void eint3_isr(void) __attribute__ ((interrupt("IRQ")));;
void delay();
/* variables */
int dither_count2 = 0;
int dither_count3 = 0;
static int nLed = 0;
/*****************************************************************************
// Function name : Main
// Description : JXARM9-2410 中断实验主程序
// 完成功能:
// 外部中断按键引发中断
// Return type : void
// Argument : void
*****************************************************************************/
void Main(void)
{
/* 配置系统时钟 */
ChangeClockDivider(2,1);
U32 mpll_val = 0 ;
mpll_val = (92<<12)|(1<<4)|(1);
ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);
/* 中断初始化 */
Isr_Init();
/* 初始化端口 */
Port_Init();
/* 初始化串口 */
Uart_Init(0,115200);
Uart_Select(0);
/* 打印提示信息 */
PRINTF("\n---外部中断测试程序---\n");
PRINTF("\n请将UART0与PC串口进行连接,然后启动超级终端程序(115200, 8, N, 1)\n");
PRINTF("\n外部中断测试开始\n");
/* 请求中断 */
Irq_Request(IRQ_EINT2, eint2_isr); //中断选择
//Irq_Request(IRQ_EINT3, eint3_isr);
/* 使能中断 */
Irq_Enable(IRQ_EINT2);
//Irq_Enable(IRQ_EINT3);
dither_count2 = 0;
dither_count3 = 0;
while(1)
{
delay();
dither_count2++;
dither_count3++;
}
}
/*****************************************************************************
// Function name : eint2_isr
// Description : EINT2中断处理程序
// Return type : int
// Argument : void
*****************************************************************************/
void eint2_isr(void)
{
Irq_Clear(IRQ_EINT2);
if(dither_count2 > 10)
{
dither_count2 = 0;
(*(U8*)0x20007000)=0x0; //中断发生时,数码管显示
(*(U8*)0x20006000)=0x80;
(*(U8*)0x20005000)=nLed; //LED亮灭切换
nLed=~nLed;
}
}
/*****************************************************************************
// Function name : eint3_isr
// Description : EINT3中断处理程序
// Return type : int
// Argument : void
*****************************************************************************/
void eint3_isr(void)
{
Irq_Clear(IRQ_EINT3);
if(dither_count3 > 10)
{
dither_count3 = 0;
(*(U8*)0x20007000)=0x0; //中断发生时,数码管显示
(*(U8*)0x20006000)=0x90;
(*(U8*)0x20005000)=0x01;delay(); //LED依次亮一下
(*(U8*)0x20005000)=0x02;delay();
(*(U8*)0x20005000)=0x04;delay();
(*(U8*)0x20005000)=0x08;delay();
(*(U8*)0x20005000)=0x10;delay();
(*(U8*)0x20005000)=0x20;delay();
(*(U8*)0x20005000)=0x40;delay();
(*(U8*)0x20005000)=0x80;delay();
}
}
void delay()
{
int index = 0;
for ( index = 0 ; index < 20000; index++);
}
五.结果及分析
1.中断2发生时,LED亮灭切换。
2.中断3发生时,LED从右依次亮灭。
3.中断发生,数码管显示数字。
加入中断使能语句,可使中断2和中断3发生,LED的地址为20005000,其余和之前原理相同,在中断语句部分里面加入。
六.实验总结
同时只能有一个中断发生
实验四 A/D实验
一.实验原理
1.了解模数转换的基本原理。
2.掌握模数转换的编程方法。
二.实验原理
要将模拟量转换成数字信号需经采样——>量化——>编码三个基本过程(数字化过程)。
(1)采样:按采样定理对模拟信号进行等时间间隔采样,将得到的一系列时域上的样值去代替u=f(t),即用u0、u1、…un代替u=f(t)。这些样值在时间上是离散的值,但在幅度上仍然是连续模拟量。
(2)量化:
在幅值上再用离散值来表示。方法是用一个量化因子Q去度量u0、u1、…,便得到整量化的数字量。
u0=2.4Q 2Q
u1=4.0Q 4Q
u2=5.2Q 5Q
u3=5.8Q 5Q
(3)编码:
将整量化后的数字量进行编码,以便读入和识别;编码仅是对数字量的一种处理方法。
例如:Q=0.5V/格,设用三位(二进编码)
通道0和通道1的模拟输入信号可通过实验箱的可调电阻AIN0、AIN1调节。
三.实验内容及步骤
(一)学习例程,对其关键程序与设置进行分析。
(二)
1、通过可变电阻改变模拟量输入,补充程序将模拟输入进行采集和转换,观查显示结果(在串口显示);
2、将转换后的电压值结果显示在LED上和串口上(如2.345)。
3、 自行开发。
步骤:
1) 参照模板工程ad(modules\ad\ad.apj),新建一个工程ad,添加相应的文件,并修改ad的工程设置;创建main.c 并加入到工程ad 中;
2) 根据内容编程;
3) 编译、链接、调试、运行。
四.实验程序
#include "def.h"
#include "2410lib.h"
#include "option.h"
#include "2410addr.h"
#include "interrupt.h"
void delay(int time) {
int i;
int delayLoopCount=1000;
for(;time>0;time--);
for(i=0;i<delayLoopCount;i++);
}
/********************************************************************
// Function name : Main
// Description : JXARM9-2410 A/D采样实验主程序
// 实现功能:
// 实现JXRAM9-2410的模数转换
// JXARM9-2410 UART0 <==> PC COM
// Return type : void
// Argument : void
*********************************************************************/
void Main(void)
{
/* 配置系统时钟 */
ChangeClockDivider(2,1);
U32 mpll_val = 0 ;
mpll_val = (92<<12)|(1<<4)|(1);
ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);
/* 初始化端口 */
Port_Init();
/* 初始化串口 */
Uart_Init(0,115200);
Uart_Select(0);
/* 打印提示信息 */
PRINTF("\n---AD采样程序---\n");
PRINTF("\n请将UART0与PC串口进行连接,然后启动超级终端程序(115200, 8, N, 1)\n");
PRINTF("\n从现在开始您将在超级终端上看到采样值,旋动旋钮AIN2和AIN3改变模拟输入\n");
/* 开始测试 */
Test_Adc();
while(1)
{
}
}
#define ADC_FREQ 2500000
#define u8 unsigned char
unsigned char segtable[16] =
{
/* 0 1 2 3 4 5 6 7*/
0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8,
/* 8 9 A B C D E F*/
0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e,
};
int ReadAdc(int ch); //Return type is int, Declare Prototype function
void Test_Adc(void)
{
int i;
int n1,n2,n3,n4,z;
float b0,z1;
int a0=0,a1=0,a2=0,a3=0,a4=0,a5=0,a6=0,a7=0; //Initialize variables
PRINTF("----------AD测试--------\n");
PRINTF("旋动AIN0, AIN1旋钮改变模拟输入,任意键退出\n");
while(1)
{
a0=Adc_Get_Data(0,ADC_FREQ); //模拟输入采集
b0=(float)a0/1024*3.3; //模拟输入转换并输出
PRINTF("\rAIN0: %04d,NUM0: %04f",a0,b0);
z=b0*1000; //将转换后的的电压值在数码管上输出
n4=z%10;
n3=(z/10)%10;
n2=(z/100)%10;
n1=z/1000;
*((u8*)0x20007000)=0x3e;
*((u8*)0x20006000)=segtable[n4];
delay(10000);
*((u8*)0x20007000)=0x3d;
*((u8*)0x20006000)=segtable[n3];
delay(10000);
*((u8*)0x20007000)=0x3b;
*((u8*)0x20006000)=segtable[n2];
delay(10000);
*((u8*)0x20007000)=0x37;
*((u8*)0x20006000)=(segtable[n1]&0x7f);
delay(10000);
}
rADCCON=(0<<14)|(19<<6)|(7<<3)|(1<<2); //stand by mode to reduce power consumption
PRINTF("\n");
PRINTF("--------AD测试结束------\n\n");
}
五.结果及分析
1.扭动旋钮改变电阻,串口上输出模拟量及转换后的输出电压值。
2.转换后的电压值在数码管上显示。
语句a0=Adc_Get_Data(0,ADC_FREQ)可获取通道0的模拟输入值,然后通过公式(float)a0/1024*3.3可得到数字输出值。可在串口上显示。再根据算式将各个位数字取出,便可实现在数码管上显示。
六.实验总结
将各位取出时,可选择小数点后的位数,导致n的数量增多。
在将模拟量转换为数字量的时候,要进行float类型强制转换。
实验五 系统时钟实验
一.实验目的
1.了解实时时钟在嵌入式系统中的作用。
2.掌握实时时钟的使用。
二.实验原理
在一个嵌入式系统中,实时时钟单元可以提供可靠的时钟,包括时分秒和年月日;即使在系统处于关机状态下它也能够正常工作(通常采用后备电池供电)。
三.实验内容及步骤
(一)学习与分析实验例程,学习时钟寄存器的设置;
(二)
1.补充程序,设置与修改当前的日期和时间;实现闹钟告警功能(设05S时报警),使能秒时钟告警 ;
2.将时分秒在数码管上显示出来。
3.自行开发。
步骤:
(1)参照模板工程rtc(modules\rtc\rtc.apj),新建一个工程rtc,添加相应的文件,并修改rtc的工程设置;
(2)创建main.c并加入到工程rtc中;
(3)根据内容编程。编译rtc,下载程序并运行,通过超级终端和数码管看输出结果。
四.实验程序
#include "def.h"
#include "2410lib.h"
#include "option.h"
#include "2410addr.h"
#include "interrupt.h"
/* 表示日期、时间的数据结构 */
typedef struct ST_DATE
{
short year; // 年
char mon; // 月
char day; // 日
char week_day; // 星期
char hour; // 时
char min; // 分
char sec; // 秒
} st_date;
void display();
void delay(int time);
extern unsigned char seg7table[16];
unsigned char loc[6]={
/* 从左到右的数码管位选 */
0x1f,0x2f,0x37,0x3b,0x3d,0x3e};
/* 全局变量 */
int led_index = 0;
int ext0_count = 0;
int table[6]={0};
/* functions */
void rtc_tick_isr(void) __attribute__ ((interrupt("IRQ")));;
void rtc_int_isr(void) __attribute__ ((interrupt("IRQ")));;
/*****************************************************************************
// Function name : rtc_set_date
// Description : 修改实时时钟当前时间、日期
// Return type : void
// Argument : p_date, 待设置的日期
*****************************************************************************/
void rtc_set_date(st_date* p_date)
{
rRTCCON = 0x01;
rBCDYEAR = p_date->year;
rBCDMON = p_date->mon;
rBCDDAY = p_date->day;
rBCDDATE = p_date->week_day;
rBCDHOUR = p_date->hour;
rBCDMIN = p_date->min;
rBCDSEC = p_date->sec;
rRTCCON = 0x00;
}
/*****************************************************************************
// Function name : rtc_get_date
// Description : 获取实时时钟当前时间、日期
// Return type : void
// Argument : p_date, 返回日期的指针
*****************************************************************************/
void rtc_get_date(st_date* p_date)
{
rRTCCON = 0x01;
p_date->year = rBCDYEAR ;
p_date->mon = rBCDMON ;
p_date->day = rBCDDAY ;
p_date->week_day= rBCDDATE ;
p_date->hour = rBCDHOUR ;
p_date->min = rBCDMIN ;
p_date->sec = rBCDSEC ;
rRTCCON = 0x00;
}
/*****************************************************************************
// Function name : rtc_tick_init
// Description : 初始化S3C2410的TICK定时器
// Return type : void
// Argument : tick, 设置的TICK频率(时钟滴答的周期为 (1+tick)/128秒)
*****************************************************************************/
void rtc_tick_init( char tick )
{
Irq_Request(IRQ_TICK, rtc_tick_isr);
rRTCCON = 0x0; //No reset[3], Merge BCD counters[2], BCD clock select XTAL[1], RTC Control disable[0]
rTICNT = (tick&0x7f)|0x80; /*TICK 中断使能,周期为(1+tick)/128秒*/
Irq_Enable(IRQ_TICK);
}
/*****************************************************************************
// Function name : rtc_alarm_set
// Description : 设置S3C2410的告警时间以及方式
// Return type : void
// Argument : p_date, 告警的时间
// mode, 告警模式
*****************************************************************************/
void rtc_alarm_set(st_date* p_date, unsigned char mode)
{
Irq_Request(IRQ_RTC, rtc_int_isr);
rRTCCON = 0x01;
rALMYEAR = p_date->year;
rALMMON = p_date->mon;
rALMDATE = p_date->day;
rALMHOUR = p_date->hour;
rALMMIN = p_date->min;
rALMSEC = p_date->sec;
rRTCALM = mode;
rRTCCON = 0x00;
Irq_Enable(IRQ_RTC);
}
/*****************************************************************************
// Function name : Main
// Description : JXARM9-2410 实时时钟实验主程序
// 完成功能:
// 时钟滴答:每秒钟刷新数码管显示
// 设置当前日期、时间
// 动态刷新当前日期、时间,通过串口打印出来
// 时间告警功能:每分钟的第5秒告警,并进行跑马灯显示
// Return type : void
// Argument : void
*****************************************************************************/
void Main(void)
{
int old_index ;
st_date m_date;
/* 配置系统时钟 */
ChangeClockDivider(2,1);
U32 mpll_val = 0 ;
mpll_val = (92<<12)|(1<<4)|(1);
ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);
/* 中断初始化 */
Isr_Init();
/* 初始化端口 */
Port_Init();
/* 初始化串口 */
Uart_Init(0,115200);
Uart_Select(0);
/* 打印提示信息 */
PRINTF("\n---实时时钟测试程序---\n");
PRINTF("\n请将UART0与PC串口进行连接,然后启动超级终端程序(115200, 8, N, 1)\n");
PRINTF("\n实时时钟测试开始\n");
/* 采用BCD编码,如20##年需要设置的值为0x2004 */
m_date.year = 0x15; m_date.mon = 0x05;
m_date.day = 0x07;
m_date.week_day = 0x04;
m_date.hour = 0x20;
m_date.min = 0x50;
m_date.sec = 0x55;
/* 修改当前日期和时间 */
rtc_set_date(&m_date);
m_date.sec = 0x05; //设置报警时间
/* 设置告警的时间及方式,0x41表示使能RTC告警,以及使能秒时钟告警 */
rtc_alarm_set(&m_date,0x41);
rtc_tick_init(127);
old_index = led_index;
PRINTF("\r\n\r\n");
while(1)
{
if(old_index != led_index) /* 每隔一秒更新一次数据 */
{
rtc_get_date(&m_date);
old_index = led_index;
exchange(&m_date);
display();
PRINTF( /* 时钟数据为BCD码格式,以16进制显示 */
"\b\b\b\b\b\b\b\b%02x:%02x:%02x", m_date.hour, m_date.min, m_date.sec);
}
};
}
/*****************************************************************************
// Function name : rtc_tick_isr
// Description : TICK中断处理程序,程序中设置每秒钟引发一次中断
// Return type : int
// Argument : void
*****************************************************************************/
void rtc_tick_isr(void)
{
Irq_Clear(IRQ_TICK); /* 清除TICK中断 */
// *((unsigned char*) 0x02000006) = 0x00;
// *(unsigned char*)0x02000004 = seg7table[led_index%10];
led_index++;
}
/*****************************************************************************
// Function name : rtc_int_isr
// Description : rtc中断处理程序,程序中设置每分钟的第5秒引发该中断
// Return type : int
// Argument : void
*****************************************************************************/
void rtc_int_isr(void)
{
Irq_Clear(IRQ_RTC); /*清除RTC中断 */
// if(ext0_count&1)
// *(unsigned char*)0x2000000 = 0x0f;
// else
// *(unsigned char*)0x2000000 = 0xff;
ext0_count++;
PRINTF("\r\nAlarm\r\n ");
}
/**********************************************************************
//name: exchange
//description: 将BCD码转化为数组形式
//return type: void
//argument: p_data
***********************************************************************/
int exchange(st_date* p_date) {
table[0]=(p_date->hour & 0xf0)>>4; //控制时分秒的显示
table[1]=p_date->hour & 0x0f;
table[2]=(p_date->min & 0xf0)>>4;
table[3]=p_date->min & 0x0f;
table[4]=(p_date->sec & 0xf0)>>4;
table[5]=p_date->sec & 0x0f;
}
/**********************************************************************
//name: display
//description: 数码管显示
//return type: void
//argument: void
***********************************************************************/
void display() //数码管显示
{
int i,count=90; // 调节count使显示正好在1s内
while(count--) {
for(i=0;i<6;i++) {
*((U8*)0x20007000)=loc[i];
*((U8*)0x20006000)=seg7table[table[i]]; /*调用数组str1*/
delay(1);
}
}
*((U8*)0x20007000)=0x3f; // 关数码管
} /*end for display*/
/*******************************************/
/* Function name: 循环延时子程序
/* Description: 循环‘time’次
/* Return type: void
/* Input type: int time
/* Argument: 循环延时计数器
*/
/*******************************************/
void delay(int time) {
int i;
int delayLoopCount=1000;
for(;time>0;time--)
for(i=0;i<delayLoopCount;i++);
}
五.结果及分析
运行程序,串口和数码管会显示时间,但是不同步,当每分钟的第三秒,串口显示报警。
六.实验总结
由于延迟或者其他原因,串口时间与数码管时间不同步,而且报警时间与预期的也不同步。
实验六 看门狗实验
一.实验目的
1.了解WATCHDOG的作用。
2.掌握WATCHDOG定时器的使用方法。
二.实验原理
看门狗定时器(WDT,Watch Dog Timer)是单片机的一个组成部分,它实际上是一个计数器,一般给看门狗一个大数,程序开始运行后看门狗开始倒计数。如果程序运行正常,过一段时间CPU应发出指令让看门狗复位,重新开始倒计数。如果看门狗减到0就认为程序没有正常工作,强制整个系统复位。
看门狗定时器是单片机的一个组成部分,在单片机程序的调试和运行中都有着重要的意义。它的主要功能是在发生软件故障时,通过使器件复位(如果软件未将器件清零)将单片机复位。也可以用于将器件从休眠或空闲模式唤醒,看门狗定时器对微控制器提供了独立的保护系统,当系统出现故障时,在可选的超时周期之后,看门狗将以RESET信号作出响应,像x25045就可选超时周期为1.4秒、600毫秒、200毫秒三种。当你的程序死机时,x25045就会使单片机复位。
三.实验内容及步骤
(一)学习与分析例程;
(二)
1.在时钟实验的基础上增加看门狗代码,使看门狗的周期为2S左右,打开看门狗复位功能,不喂狗,观察是否复位;
2.使看门狗的周期为2S左右,打开看门狗复位功能,每秒喂狗一次,观察是否复位;
3.编程,使看门狗的周期为2S左右,打开看门狗复位功能,每3S喂狗一次,观察是否复位;
4.自行发挥
步骤:
1) 参照模板工程watchdog(modules\rtc\watchdog.apj),新建一个工程watchdog,添加相应的文件,并修改watch 的工程设置;
2) 创建main.c 并加入到工程watch 中;
3) 根据内容编程;
4) 编译main,下载程序并运行,通过超级终端看是否复位;
四.实验程序
#include "def.h"
#include "2410lib.h"
#include "option.h"
#include "2410addr.h"
#include "interrupt.h"
extern unsigned char seg7table[];
/* 表示日期、时间的数据结构 */
typedef struct ST_DATE
{
short year; // 年
char mon; // 月
char day; // 日
char week_day; // 星期
char hour; // 时
char min; // 分
char sec; // 秒
} st_date;
/* 全局变量 */
int led_index = 0;
int ext0_count = 0;
int flag=0;
/* functions */
void rtc_tick_isr(void) __attribute__ ((interrupt("IRQ")));;
void rtc_int_isr(void) __attribute__ ((interrupt("IRQ")));;
#define WDT_ENABLE (0x01<<5)
#define WDT_INT_ENABLE (0x01<<2)
#define WDT_RST_ENABLE (0x01<<0)
#define WDT_CLK_SEL (0X3 <<3) /* 1/128 */
#define WDT_PRE_SCALER ((PCLK/1000000-1) <<8) /* 49 */
/********************************************************************
// Function name : watchdog_init
// Description : 看门狗初始化
// Return type : void
// Argument :
*********************************************************************/
void watchdog_init()
{
rWTCNT = 8448 * 2; /* 设置看门狗初始值 */
rWTCON = WDT_ENABLE | WDT_RST_ENABLE | WDT_CLK_SEL | WDT_PRE_SCALER; /* 打开看门狗 */ /* 打开看门狗 */
}
/*****************************************************************************
// Function name : rtc_set_date
// Description : 修改实时时钟当前时间、日期
// Return type : void
// Argument : p_date, 待设置的日期
*****************************************************************************/
void rtc_set_date(st_date* p_date)
{
rRTCCON = 0x01;
rBCDYEAR = p_date->year;
rBCDMON = p_date->mon;
rBCDDAY = p_date->day;
rBCDDATE = p_date->week_day;
rBCDHOUR = p_date->hour;
rBCDMIN = p_date->min;
rBCDSEC = p_date->sec;
rRTCCON = 0x00;
}
/*****************************************************************************
// Function name : rtc_get_date
// Description : 获取实时时钟当前时间、日期
// Return type : void
// Argument : p_date, 返回日期的指针
*****************************************************************************/
void rtc_get_date(st_date* p_date)
{
rRTCCON = 0x01;
p_date->year = rBCDYEAR ;
p_date->mon = rBCDMON ;
p_date->day = rBCDDAY ;
p_date->week_day= rBCDDATE ;
p_date->hour = rBCDHOUR ;
p_date->min = rBCDMIN ;
p_date->sec = rBCDSEC ;
rRTCCON = 0x00;
}
/*****************************************************************************
// Function name : rtc_tick_init
// Description : 初始化S3C2410的TICK定时器
// Return type : void
// Argument : tick, 设置的TICK频率(时钟滴答的周期为 (1+tick)/128秒)
*****************************************************************************/
void rtc_tick_init( char tick )
{
Irq_Request(IRQ_TICK, rtc_tick_isr);
rRTCCON = 0x0; //No reset[3], Merge BCD counters[2], BCD clock select XTAL[1], RTC Control disable[0]
rTICNT = (tick&0x7f)|0x80; /*TICK 中断使能,周期为(1+tick)/128秒*/
Irq_Enable(IRQ_TICK);
}
/*****************************************************************************
// Function name : rtc_alarm_set
// Description : 设置S3C2410的告警时间以及方式
// Return type : void
// Argument : p_date, 告警的时间
// mode, 告警模式
*****************************************************************************/
void rtc_alarm_set(st_date* p_date, unsigned char mode)
{
Irq_Request(IRQ_RTC, rtc_int_isr);
rRTCCON = 0x01;
rALMYEAR = p_date->year;
rALMMON = p_date->mon;
rALMDATE = p_date->day;
rALMHOUR = p_date->hour;
rALMMIN = p_date->min;
rALMSEC = p_date->sec;
rRTCALM = mode;
rRTCCON = 0x00;
Irq_Enable(IRQ_RTC);
}
/*****************************************************************************
// Function name : Main
// Description : JXARM9-2410 看门狗实验主程序
// 完成功能:
// 在实时时钟实验的基础上添加看门狗功能,并在时钟滴答
// 中断中实现喂狗处理.
//
// Return type : void
// Argument : void
*****************************************************************************/
void Main(void)
{
int old_index ;
st_date m_date;
/* 配置系统时钟 */
ChangeClockDivider(2,1);
U32 mpll_val = 0 ;
mpll_val = (92<<12)|(1<<4)|(1);
ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);
/* 中断初始化 */
Isr_Init();
/* 初始化端口 */
Port_Init();
/* 初始化串口 */
Uart_Init(0,115200);
Uart_Select(0);
/* 打印提示信息 */
PRINTF("\n---看门狗测试程序---\n");
PRINTF("\n请将UART0与PC串口进行连接,然后启动超级终端程序(115200, 8, N, 1)\n");
PRINTF("\n看门狗测试开始\n");
/* 采用BCD编码,如20##年需要设置的值为0x2004 */
m_date.year = 0x2000+0x15 ;
m_date.mon = 0x05 ;
m_date.day = 0x07 ;
m_date.week_day = 0x04 ;
m_date.hour = 0x20 ;
m_date.min = 0x35 ;
m_date.sec = 0x00 ;
/* 修改当前日期和时间 */
rtc_set_date(&m_date);
m_date.sec = 0x05 ;
/* 设置告警的时间及方式,0x41表示使能RTC告警,以及使能秒时钟告警 */
rtc_alarm_set(&m_date, 0x41);
rtc_tick_init(127);
watchdog_init(); //打开看门狗复位功能
old_index = led_index;
PRINTF("请在2秒内喂狗,否则系统将在约2秒后复位\n\n");
while(1)
{
if(old_index != led_index) /* 每隔一秒更新一次数据 */
{
rtc_get_date(&m_date);
old_index = led_index;
PRINTF( /* 时钟数据为BCD码格式,以16进制显示 */
"\b\b\b\b\b\b\b\b%02x:%02x:%02x", m_date.hour, m_date.min, m_date.sec);
}
};
}
/*****************************************************************************
// Function name : rtc_tick_isr
// Description : TICK中断处理程序,程序中设置每秒钟引发一次中断
// 为避免看门狗复位在此处喂狗
// Return type : int
// Argument : void
*****************************************************************************/
void rtc_tick_isr(void)
{
Irq_Clear(IRQ_TICK); /* 清除TICK中断 */
/* 喂狗 */
if(flag>=3) //此处更改喂狗的周期
{
flag=0;
rWTCNT=8448 * 2;
PRINTF("\r\n喂狗成功\r\n");
}
}
/*****************************************************************************
// Function name : rtc_int_isr
// Description : rtc中断处理程序,程序中设置每分钟的第5秒引发该中断
// Return type : int
// Argument : void
*****************************************************************************/
void rtc_int_isr(void)
{
Irq_Clear(IRQ_RTC); /*清除RTC中断 */
// if(ext0_count&1)
// *(unsigned char*)0x2000000 = 0x0f;
// else
// *(unsigned char*)0x2000000 = 0xff;
ext0_count++;
PRINTF("\r\nAlarm\r\n ");
}
五.结果及分析
1.打开看门狗复位功能,不喂狗,看门狗复位。
2.使看门狗周期为2s左右,打开看门狗复位功能,每秒喂狗一次,看门狗不复位。
3.每3s喂狗一次,看门狗复位。
喂狗相当于给看门狗一个使能信号,阻止看门狗复位。但当不喂狗或者喂狗的周期大于看门狗的周期时,看门狗也会复位。
六.实验总结
正确区分看门狗复位与机器故障引起的复位,正确使用喂狗条件与周期。
实验七 PWM实验
一.实验目的
1.了解PWM的基本原理。
2.掌握PWM控制的编程方法。
二.实验原理
1.PWM是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。
许多微控制器内部都包含PWM控制器。一般都可以选择接通时间和周期。占空比是接通时间与周期之比;调制频率为周期的倒数。
设置提供调制方波的片上定时器/计数器的周期;在PWM控制寄存器中设置接通时间;启动定时器。
2.音乐中的音名与频率的对应关系
三.实验内容及步骤
(一)学习与分析例程;
(二)
1.编写程序对PWM控制器输出8000Hz 2/3占空比的数字信号控制峰鸣器;
2.编写程序改变PWM控制器输出频率,如频率从4000HZ到14000HZ, 使用2/3的占空比;
3.编写程序改变PWM控制器输出占空比,如频率1000HZ, 使用1/100 - 95/100的占空比。
4.编写程序实现一句音乐。
步骤:
(1)新建一个工程,添加相应的文件,并修改相应的工程设置;
(2)创建main.c文件,将该文件加入到工程中;
(3)根据内容编写程序输出到蜂鸣器;
(4)编译、下载、运行、调试程序、听蜂鸣器输出结果;
四.实验程序
#include "def.h"
#include "2410lib.h"
#include "option.h"
#include "2410addr.h"
#include "interrupt.h"
void test_pwm();
/********************************************************************
// Function name : Main
// Description : JXARM9-2410 PWM实验主程序
// 实现功能:
// 实现JXARM9-2410 PWM方式控制蜂鸣器
// Return type : void
// Argument : void
*********************************************************************/
void Main(void)
{
unsigned char data[6] = {0, 1, 2, 3, 4, 5};
/* 配置系统时钟 */
ChangeClockDivider(2,1);
U32 mpll_val = 0 ;
mpll_val = (92<<12)|(1<<4)|(1);
ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);
/* 初始化端口 */
Port_Init();
/* 初始化串口 */
Uart_Init(0,115200);
Uart_Select(0);
/* 打印提示信息 */
PRINTF("\n---蜂鸣器测试程序---\n");
/* 端口设置 */
rGPBUP = rGPBUP & ~(0x1f) | 0x1f; //GPB4 ~ 0
rGPBCON = rGPBCON & ~(0x3ff) | 0x2aa; //Function Setting TCLK0, TOUT3 ~ 0
rGPGUP = rGPGUP & ~(0x800) | 0x800; //GPG11
rGPGCON = rGPGCON & ~(0xc00000) | 0xc00000; //TCLK1
rGPHUP = rGPHUP & ~(0x200) | 0x200; //GPH9
rGPHCON = rGPHCON & ~(0x3<<18) | (0x2<<18); //CLKOUT0
rMISCCR = rMISCCR & ~(0xf0) | 0x40; //Select PCLK with CLKOUT0
/* 开始测试 */
test_pwm();
while(1);
}
/*****************************************************************************
// Function name : test_pwm
// Description : 测试PWM,通过蜂鸣器输出脉冲
// Return type : int
// Argument : void
*****************************************************************************/
void test_pwm()
{
rTCFG0 = 0xff;
rTCFG1 = 0x1;
int N;
N = PCLK / 256 / 4 / 8000; //输出脉冲:频率8000Hz, 2/3占空比
rTCNTB0 = N;
rTCMPB0 = 2 * N / 3;
rTCON = 0x9;
Delay(100);
int feq;
for (feq = 4000; feq <= 14000; feq=feq+1000)
//输出脉冲:频率从4000HZ到14000HZ, 使用2/3的占空比
{
N = PCLK / 256 / 4 / feq;
rTCNTB0 = N;
rTCMPB0 = 2 * N / 3;
rTCON = 0xa;
rTCON = 0x9;
Delay(100);
rTCON = 0x0;
}
N = PCLK / 256 / 4 / 1000; //输出脉冲:频率1000HZ, 使用1/100 - 95/100的占空比
rTCNTB0 = N;
int i;
int N1;
for (i = 1; i <= 19; i++)
{
N1 = i*N / 100;
rTCMPB0 = N1;
rTCON = 0xa;
rTCON = 0x9;
Delay(100);
rTCON = 0x0;
}
int song[38]={659,659,659,659,659,698,659,523,578,659,698,988,523,578,578,659,880,440,523,494,494,659,659,659,659,784,659,698,698,880,698,659,698,698,578,578,698,578};
//德国战车 中低音
for (i=0; i<59; i++)
{
N=PCLK/256/4/song[i];
rTCNTB0=N;
rTCMPB0=2*N/3;
rTCON=0xa;
rTCON=0x9;
Delay(50);
rTCON=0x0;
}
/* 设置定时器的预分频率值:TIME0/1=255, TIME2/3=0, TIME4/5=0*/
/* 设置定时器的工作模式:中断模式,设置分频率值:TIME0为1/4,其他为1/2*/
/* 输出脉冲:频率从4000HZ到14000HZ, 使用2/3的占空比*/
/* 输出脉冲:频率1000HZ, 使用1/100 - 95/100的占空比*/
}
五.结果及分析
1.运行程序,实验仪器控制蜂鸣器依次产生不同频率的声音。
分析:不同的频率对因不同的声音,控制频率的变化可产生不同的声音。
六.实验总结
1.产生的音乐与实际音乐有差别是因为PWM中,两个音之间的停顿一样,而且频率采取了取舍。
实验八 步进电机实验
一.实验目的
1.了解步进电机的原理以及控制方法。
二.实验原理
步进电机是将电脉冲信号转变为角位移或线位移的开环控制元件。在非超载的情况下,电机的转速、停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响,即给电机加一个脉冲信号,电机则转过一个步距角。这一线性关系的存在,加上步进电机只有周期性的误差而无累积误差等特点。使得在速度、位置等控制领域用步进电机来控制变得非常的简单。
单三拍方式
电机的定子上有六个均布的磁极,其夹角是60度。各磁极上套有线圈,按图连成A、B、C三相绕组。设转子上均布40个小齿。所以每个齿的齿距为。三相绕组按A→B→C→A顺序循环通电时,转子会按顺时针方向,以每个通电脉冲转动3度规律步进式转动起来。若改变通电顺序,按A→C→B→A顺序循环通电,则转子就按逆时针方向以每个通电脉冲转动3度律转动。因为每一瞬间只有一相绕组通电,并且按三种通电状态循环通电,故称为单三拍运行方式。三相步进电动机还有两种通电方式,它们分别是双三拍运行,即按AB→BC→CA→AB顺序循环通电的方式,以及单、双六拍运行,即按A→AB→B→BC→C→CA→A顺序循环通电的方式。六拍运行时的步矩角将减小一半。反应式步进电动机的步距角可按下式计算:,式中Er——转子齿数;N——运行拍数,N=km,m为步进电动机的绕组相数,k=1或2。
本实验的步进电机使用四相式步进电机,工作模式为两相四拍。
脉冲分配信号:整步模式脉冲分配
三.实验内容及步骤
1.编写程序实现步进电机正转;
2.编写程序实现步进电机反转;
步骤:
1)参照模板工程stepper (modules\stepper\ stepper.apj),新建一个工程stepper,添加相应的文件,并修改stepper的工程设置;
2)创建stepper.c文件,将该文件加入到工程中;
3)编写程序;
4)编译、下载、运行、调试程序、输出结果;
四.实验程序
void delay(int count);
void delay(int time);
#define U8 unsigned char
//ioport unsigned port100e;
/* functions */
void delay(int count);
// TODO
// 整步模式正转脉冲或反转脉冲
void Main(void)
{
int row = 0;
for( ; ; )
{
(*(U8*)0x20002000)= 0x5;
delay(1000);
(*(U8*)0x20002000)= 0x9;
delay(1000);
(*(U8*)0x20002000)= 0xA;
delay(1000);
(*(U8*)0x20002000)= 0x6;
delay(1000); // TODO
(*(U8*)0x20002000)= 0x6;
delay(1000);
(*(U8*)0x20002000)= 0xA;
delay(1000);
(*(U8*)0x20002000)= 0x9;
delay(1000);
(*(U8*)0x20002000)= 0x5;
delay(1000);
}
}
/****************************************
// Function name : delay
// Description : 延时子程序
// Return type : void
// Argument : count,延时的数值
******************************************/
void delay( int count )
{
int cnt;
for( count = count; count>0; count--)
for( cnt = 0; cnt < 100; cnt++);
}
五.结果及分析
运行程序后,电机先正转,然后反转。而数码管和LED灯正转时从左向右依次显示,反转时从右向左依次显示。
电机分为四个方向(不开电扭动可以感觉到),控制四个方向循环即可完成正转反转。LED和数码管显示原理与之前相同。
六.实验总结
注意电机正转和反转时控制的数组顺序不同,LED和数码管也如此。
实验九 串口通讯实验
一.实验目的
1.掌握ARM的串行口工作原理。
2.学习编程实现ARM的UART通讯。
3.掌握S3C2440寄存器配置方法。
二.实验原理
1.UART(Universal Asynchronous Receiver and Transmitter,通用异步收发器),采用异步串行通信方式。UART以字符为单位进行数据传输,每个字符的传输格式如图所示,包括线路空闲状态(高电平)、起始位(低电平)、5~8位数据位、校验位(可选)和停止位(位数可以是1、1.5或2位)。
2. S3C2440A的UART特性:
(1)基于DMA或基于中断操作的RxD0,TxD0,RxD1,TxD1,RxD2和TxD2
(2)UART通道0,1和2带IrDA 1.0和64字节FIFO
(3)UART通道0和1带nRTS0,nCTS0,nRTS1和nCTS1
(4)支持握手发送/接收
(5)S3C2440A的UART包括了可编程波特率,红外(IR)发送/接收,插入1个或2个停止位,5位、6位、7位或8位的数据宽度以及奇偶校验。
三.实验内容及步骤
(一)学习与分析相关例程,分析有关UART寄存器的设置;
(二)
1.补充程序,实现对串口的初始化和回环测试。接收来自串口(通过超级终端)的字符并将接收到的字符发送到超级终端;
2.在1的基础上将终端输入字符显示在实验箱的数码管上;
3.自行开发,如显示一串字符等。
步骤:
1) 参照模板工程uart(modules\uart\uart.apj),新建一个工程uart,添加相应的文件,
并修改uart 的工程设置;
2) 加入如下文件到uart 中:common\2440lib.c、;asm\2440init.s、asm\2440slib.s。
3) 参照上节内容编写串口操作主函数,并保存为main.c 文件,将该文件加入到工程中;
4) 参考模板工程uart 对uart 工程进行设置,然后编译uart;
5) 将计算机的串口接到教学实验系统的uart0 上;
6) 运行超级终端,选择正确的串口号,并将串口设置为:波特率(115200)、奇偶校验
(None)、数据位数(8)和停止位数(1),无流控,打开串口。
7) 下载程序并运行,如果程序运行正确,在超级终端中输入的数据将回显到超级终端上。
四.实验程序
/* 包含文件 */
#include "def.h"
#include "2410lib.h"
#include "option.h"
#include "2410addr.h"
#include "interrupt.h"\
void showChar(char ch);
void showString(char *str);
/********************************************************************
// Function name : Main
// Description : JXARM9-2410 串口通信实验主程序
// 实现功能:
// 实现JXRAM9-2410与PC机的串口通讯
// JXARM9-2410 UART0 <==> PC COM
// Return type : void
// Argument : void
*********************************************************************/
void Main(void)
{
/* 配置系统时钟 */
ChangeClockDivider(2,1);
U32 mpll_val = 0 ;
mpll_val = (92<<12)|(1<<4)|(1);
ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);
/* 初始化端口 */
Port_Init();
// TODO 串口初始化
/* 打印提示信息 */
Uart_Init(0, 115200);
Uart_Select(0);
PRINTF("\n---UART测试程序---\n");
PRINTF("\n请将UART0与PC串口进行连接,然后启动超级终端程序(115200, 8, N, 1)\n");
PRINTF("\n从现在开始您从超级中断发送的字符将被回显在超级终端上\n");
char ch;
char *st;
char *st1;
ch = Uart_Getch();
Uart_SendByte(ch);
st1 = st;
*st++ = ch;
/* 开始回环测试 */
while (ch != '\r')
{
// TODO
*st++ = ch;
showChar(ch);
ch = Uart_Getch();
Uart_SendByte(ch);
// 串口回环测试
}
Uart_SendString(st1);
/*
while (1)
{
showString(st1);
}
*/
//显示字符串
/*
char *st;
Uart_GetString(st);
Uart_SendString(st);
*/
}
void showChar(char ch)
{
unsigned char segtable[16] =
{
/* 0 1 2 3 4 5 6 7*/
0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8,
/* 8 9 A B C D E F*/
0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e,
};
*((unsigned char *)0x20007000) = 0x3b;
if ((ch >= '0')&(ch <= '9'))
{
*((unsigned char*)0x20006000) = segtable[ch - '0'];
Delay(1);
}
else if ((ch >= 'A')&(ch <= 'F'))
{
*((unsigned char*)0x20006000) = segtable[ch - 'A' + 10];
Delay(1);
}
else
{
*((unsigned char*)0x20006000) = 0x00;
}
}
void showString(char *str)
{
char *show = str;
unsigned char segtable[16] =
{
/* 0 1 2 3 4 5 6 7*/
0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8,
/* 8 9 A B C D E F*/
0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e,
};
int i = 0;
int j;
while (*show != '\r')
{
for (j = 0; j < 1000;j++)
{
*((unsigned char*)0x20007000) = ~(1 << i) & 0x3f;
if ((*show >= '0')&(*show <= '9'))
{
*((unsigned char*)0x20006000) = segtable[*show - '0'];
Delay(1);
}
else if ((*show >= 'A')&(*show <= 'F'))
{
*((unsigned char*)0x20006000) = segtable[*show - 'A' + 10];
Delay(1);
}
else
{
*((unsigned char*)0x20006000) = 0x00;
}
show++;
i++;
i %= 6;
}
}
}
五.结果及分析
1.运行程序,在键盘上输入的字符显示在超级终端和数码管上。
2.运行程序,数码管显示一串字符。
分析:语句
ch=Uart_Getch();
Uart_SendByte(ch);
即用来接收终端输入字符并传送。将其显示到数码管上则需要将其进行筛选,满足要求即可输出。而对于显示一串字符,则用到以下语句来获取字符串的值:
Uart_GetString(&a);
Uart_SendString(&a);
接着在0—F之间比较输出。
六.实验总结
1.三个实验不能同时运行,否则机器复位。
实验十 LCD显示实验
一.实验目的
1.了解LCD显示图形的方法。
2.了解LCD显示字符的方法(本次实验显示汉字)。
二.实验原理
LCD显示器是通过给不同的液晶单元供电,控制其光线的通过与否,从而达到显示的目的。因此,LCD的驱动控制归于对每个液晶单元通断电的控制,每个液晶单元都对应着一个电极,对其通电,便可使用光线通过(也有刚好相反的,即不通电时光线通过,通电时光线不通过)。
光源的提供方式有两种:透射式和反射式。笔记本电脑的LCD显示屏即为透射式,屏后面有一个光源,因此外界环境可以不需要光源。而一般微控制器上使用的LCD为反射式,需要外界提供光源,靠反射光来工作。
LCD的驱动控制——扫描器控制方式:一般带有驱动模块的LCD显示屏使用总线驱动方式,这种LCD可以方便地与各种低档单片机进行接口,如8051系列单片机。由于LCD已经带有驱动硬件电路,因此模块给出的是总线接口,便于与单片机的总线进行接口。驱动模块具有八位数据总线,外加一些电源接口和控制信号。而且还自带显示缓存,只需要将要显示的内容送到显示缓存中就可以实现内容的显示。由于只有八条数据线,因此常常通过引脚信号来实现地址与数据线复用,以达到把相应数据送到相应显示缓存的目的。
三.实验内容及步骤
1.学习例程,在LCD上显示图形。
2.在LCD上显示汉字。如:显示“西安电子科技大学”等。
3.自行开发。
步骤:
1)新建一个工程,添加相应的文件,并修改相应的工程设置;
2)创建dispgraph.c文件,将该文件加入到工程中;
3)编辑dispgraph.c文件,添加Main函数,并在其中执行lcd_init操作;
4)编程 ;
5)编译下载、运行、调试、查看结果。
四.实验程序
/* 包含文件 */
#include "def.h"
#include "2410lib.h"
#include "option.h"
#include "2410addr.h"
#include "interrupt.h"
#include "lcdlib.h"
//#define STN_LCD
#define TFT_8_0
void (*PutPixel)(U32,U32,U32);
void Lcd_Disp_Char(void);
void Lcd_Disp_Grap(void);
/********************************************************************
// Function name : Main
// Description : JXARM9-2410 LCD显示实验主程序
// 实现功能:
// Return type : void
// Argument : void
*********************************************************************/
void Main(void)
{
/* 配置系统时钟 */
ChangeClockDivider(2,1);
U32 mpll_val = 0 ;
mpll_val = (92<<12)|(1<<4)|(1);
ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);
/* 初始化端口 */
Port_Init();
/* 初始化串口 */
Uart_Init(0,115200);
Uart_Select(0);
/* 打印提示信息 */
PRINTF("\n---LCD测试程序---\n");
PRINTF("\n请将UART0与PC串口进行连接,然后启动超级终端程序(115200, 8, N, 1)\n");
/* LCD初始化 */
Lcd_Port_Init();
#ifdef STN_LCD
Lcd_Init(MODE_CSTN_8BIT);
Glib_Init(MODE_CSTN_8BIT);
Lcd_CstnOnOff(1);
Glib_ClearScr(0xff, MODE_CSTN_8BIT);
#else
#ifdef TFT_8_0
rGPCCON &= ~(3<<8);
rGPCCON |= (2<<8);
Lcd_Init(MODE_TFT_16BIT_640480);
Glib_Init(MODE_TFT_16BIT_640480);
Glib_ClearScr(0xffff, MODE_TFT_16BIT_640480);
Lcd_PowerEnable(0, 1);
Lcd_EnvidOnOff(1);
#else
Lcd_Init(MODE_TFT_16BIT_240320);
Glib_Init(MODE_TFT_16BIT_240320);
Glib_ClearScr(0xffff, MODE_TFT_16BIT_240320);
Lcd_PowerEnable(0, 1);
Lcd_EnvidOnOff(1);
#endif
#endif
while(1)
{
#define LCD_DISP_CHAR
//#ifdef LCD_DISP_CHAR
Lcd_Disp_Char();
//#else
//Lcd_Disp_Grap();
//#endif
int i,j;
for(j=100;j<500;j++)
for(i=100;i<500;i++)
Glib_FilledRectangle(i,j,i+50,j+100,0xf800);
}
}
void Lcd_Disp_Char(void)
{
/* 显示字符串 */
Glib_disp_hzk16(30,400,"西安电子科技大学", 0x0);
Delay(100);
return;
}
void Lcd_Disp_Grap(void)
{
int i,j;
for(j=0;j<480;j++)
for(i=0;i<640;i++) //RRRGGGBB
(*PutPixel)(i,j,0xf800);
Delay (10);
for(j=0;j<480;j++)
for(i=0;i<640;i++) //RRRGGGBB
(*PutPixel)(i,j,0x07e0);
Delay (10);
for(j=0;j<480;j++)
for(i=0;i<640;i++) //RRRGGGBB
(*PutPixel)(i,j,0x001f);
Delay (10);
for(j=0;j<480;j++)
for(i=0;i<640;i++) //RRRGGGBB
(*PutPixel)(i,j,0xffff);
Delay (10);
/*int i,j;
PRINTF("\ndis 1\n");
for(i=0;i<640;i++)
for(j=0;j<480;j++)
_PutTft16Bit_640480(i,j,*(short *)(0xf100 + (j*640 + i) * 2));*/
}
五.结果及分析
运行程序,屏幕上出现交替的图像,并同时显示字符。
六.实验总结
汉字不能输入太长,否则会出现乱码。
单片机实验报告学生姓名学号专业指导教师学院信息与电气工程学院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中数码管显示编程方法二实验仪器…
广西科技大学筹课程设计说明书课题名称单片机电子时钟的设计系别职业技术教育学院专业电子信息工程班级学号姓名报告样板指导教师I摘要单片…
题目单片机组成原理实验报告学院计算机科学与工程学院专业信息安全姓名学号20xx年12月8日实验一输入输出接口编程一实验目的1掌握K…