单片机教程网

电脑版
提示:原网页已由神马搜索转码, 内容由www.51hei.com提供.
查看:10890|回复:4

LPC2000系列Proteus仿真+代码 菜鸟的ARM学习笔记

 [复制链接]
ID:427220发表于 2018-11-15 17:50|显示全部楼层
lpc2000系列proteus仿真+代码,新手自取

菜鸟的ARM学习笔记
下面就是我学习ARM的第一阶段的记录,这段时间的学习基本上是使用Proteus配合KEIL做简单的实验(最后有实验的目录以及下载地址)。通过该阶段的学习,算是对ARM的基本结构有了了解。
该阶段主要学习资料是《基于PROTEUS的ARM虚拟开发技术》,以及另外一本ARM体系结构的书籍,感觉这类书都差不多。
学习ARM前需要的基础
  • 前辈学习ARM的经验!(我是在嵌入式开发联盟的新人区看的帖子。)
  • 掌握C语言编程。
  • 了解简单的微机算计原理知识,例如二进制,计算机程序的执行过程,总线(数据、地址、控制),软件系统(系统软件与应用软件)。
  • 听说过RISC与CISC,高级语言与低级语言的区别。
  • 最好听说过串行传输与并行传输。
  • 普林斯顿(ARM7)和哈佛结构(ARM9、10、11—)。
什么是ARM
学ARM,自然要理解ARM是什么,也好明确学习目标。网上的资料很多,“ARM是一家公司,也是一个处理器体系”……我将学ARM分为以下几类:
  • 做ARM的核心研发。也就是进ARM公司做IP核,应该是学电子之类的东西吧。
  • 买ARM的IP核,做具体的嵌入式处理器、核心板,例如三星和NXP。
  • 买ARM核心板,连接外围电路制作教育用或开发用的开发板,或者直接开发其它中断产品。
  • 买ARM开发板做产品,要做系统软件和应用软件。
3和4基本并列了。
ARM基础
任何一本介绍ARM体系结构书籍都应该有这些内容。
处理器模式
用户模式、特权模式又分为系统模式、管理模式、快中断模式、中断模式、终止模式、未定义指令终止模式。
2. 寄存器
R0-R7、R15和CPSR是所有模式共享的。
R8-R12出快中断模式有RX-fiq外所有模式共享。
R13、R14和SPSR只有用户模式和系统模式共享,其它都有似有SPSR。
R15(PC)程序计数器
R16(CPSR)程序转台寄存器
R13(SP)堆栈指针
P14(LR)链接寄存器
ARM指令集 汇编程序设计
略了,我看了,但是做Proteus仿真实验没用上,两天就忘了。
LPC2000
我买的3本ARM入门书籍中有两本都是以LPC2000系列为例的,其实从网上可以下载到具体LPC2XXX处理器的datasheet,上面的资料是最权威和详尽的。
引脚选择
PINSEL0、PINSEL1设置各个引脚的功能。
中断
中断的寄存器太多了,没记。
GPIO
做输入输出。以P0口为例,寄存器有IO0PIN、IO0SET、IO0DIR、IO0CLR。
存储器
  • LPC2000可用地址为4GB,内部2GB(0~0x7FFFFFFF),外部2GB(0x80000000~0xDFFFFFFF),高0.5GB是I/O设备地址空间(0xE0000000~0xFFFFFFFF)。
  • 内部最低128KB或256KB为Flash。
  • 高1GB(0x40000000~0x7FFFFFFF)为SRAM。其中0x40000000~0x40001FFF为片内SRAM。
  • I/O部分,低2MB(0xE0000000~0xE001FFFFF)为VPB外设空间,高2MB(0xFFE00000~0xFFFFFFFF)为AHB外设空间。
  • FLASH加速模块。
MAMCR设置是否允许加速、MAMTIM设置预取处理器时钟。
时钟
cclk、pclk
分振荡器模式和从属模式,振荡器Fosc经PLL升频为cclk,cclk经过VPB分频后为pclk。
设置cclk
PLLCFG 设置PLL倍频M,PLL分频器值P
PLLCON PLL的允许与连接
PLLSTAT 读取PLL状态
PLLFEED 使PLL设置生效
例Fosc=12MHz,cclk=60MHz,则M=60/12-1=4,因为Fcco=P*cclk*2(要求156M~320MHz)。
设置pclk
由VPBDIV设置00为4分频、01为不分频、10为二分频。
定时器
pclk定时,定时器为32位,从0计数到0xFFFFFFFF。以T0为例
T0TC,计数器初值
T0PR,定时计数器分频,pclk/(PR+1)
T0MR0~3,匹配值,当计数带到时候,按照T0MCR的设置触发不同动作。
T0MCR,计数器到达匹配值的动作(复位、中断、停止)
T0EMR,外部匹配寄存器,到达匹配值时候外部引脚的操作(MAT0.0~3)
T0CCR,外部引脚有特定动作时候,计数值存入T0CR0~3,设置是否触发中断
T0CR0~3,在T0CCR控制下存TC值。
T0TCR,复位与使能
T0IR,对应MR与CR中断
PWM
看门狗
Pclk四分频后控看门狗的32为计数器减一。
WDTC,看门狗计数器初值。
WDMOD,看门狗工作模式,可以开启和复位看门狗。
WDFEED,喂狗寄存器。
WDTV,看门狗计数器当前值。
UART
引脚RxD0,TxD0
U0RBR,暂存接受数据。
U0THR,暂存发送数据。访问它时,U0LCR的DLAB位为0。
U0IER,串口个状态的中断允许。
U0IIR,中断标志。
U0FCR,控制UART的FIFO(暂时没明白)。
U0LCR,传输模式。
U0LSR,当前状态(错误指示)。
U0DLL、U0DLM,pclk/( U0DLL U0DLM),访问时UOLCR的DLAB位为1。
SPI
全双工同步串行接口
引脚:
SCK0,串行时钟。
SSEL0,从机选择。
MISO,主机输入,从机输出。
MOSI,主机输出,从机输入。
寄存器:
S0SPCR,SPI控制。
S0SPSR,SPI状态。
S0SPDR,SPI数据。
S0SPCCR,控制SCK的频率。必须为偶数且大于等于8。(指示一个SCK周期中的pclk周期)
S0SPINT,SPI中断。
I2C
引脚:SDA,SCL
寄存器:
I2CONSET
I2CONCLR
I2CON
上面三个寄存器控制应答标志位,中断标志、停止和起始以及I2C使能。
I2STAT,I2C状态。
I2DAT,I2C数据。
I2ADR,I2C从模式地址。
I2STAT,I2C状态。
I2SCLH,高电平占空比占pclk周期个数。
I2SCLL,低电平占空比占pclk周期个数。
分频fpclk/( I2SCLH+I2SCLL)。
AD转换
引脚:AIN0~3
寄存器:
ADCR,工作模式选择。
ADDR,转换数据以及标志的暂存。
基于ProteusARM实验目录
菜鸟的ARM学习笔记(第一阶段)
  • LED闪烁——ARM的Proteus实验
  • 开关控制LED——ARM的Proteus实验
  • LCD——ARM的Proteus实验
  • UART——ARM的Proteus实验
  • Eint1外部中断——ARM的Proteus实验
  • 多个外部中断——ARM的Proteus实验
  • 中断结合串口——ARM的Proteus实验
  • 定时器——ARM的Proteus实验
  • SPI通信——ARM的Proteus实验
  • SPI通信(多从设备)——ARM的Proteus实验
  • ADC数模转换——ARM的Proteus实验
1、LED闪烁——ARM的Proteus实验
实验原理
ARM(LPC21XX)的一个I/O口接LED,通过给它送0和1来设置LED的亮和灭。
Proteus仿真电路图
步骤
KEIL
  • 创建新工程
  • 选择ARM型号(KEIL会自动生成启动代码startup.s)
  • 添加源文件,编写程序
  • 设置项目选项(是否输出hex、lst文件,设置linker script)
Proteus
  • 绘制电路图
  • 载入程序
  • 仿真
C语言源程序
/******************************************************************************/
/*                                                   */
/*           led.c:  用ARM点亮一个led并闪烁,有点浪费……               */
/*                                                   */
/******************************************************************************/
#include< LPC21xx.H>                
/*******************************************************************************
**函数名: delay()
**描述: 软件延时
********************************************************************************/
void delay (void)  {                
   unsigned volatile long i,j;
   for(i=0;i<60000;i++)
   for(j=0;j<5;j++)
   ;
}
int main(void) {
   PINSEL0 = 0;           /*设置引脚为GPIO */
   IO0DIR = 0x000001;           /*将P0.0设置为输出 */
   IO0SET = 0x000001;           /*将P0.0置1,也就是让led灭 */
   while (1)  {
           IO0CLR = 0x000001;
           delay();
           IO0SET = 0x000001;
           delay();
   }
}
2、开关控制LED——ARM的Proteus实验
实验原理
ARM的P0.1口接按钮,再通过P0.0控制LED的亮、灭。本实验的电路图以及实验均在上一个实验基础之上修改。其中电路图只多了一个开关。
Proteus仿真电路图
实验步骤略(与上一实验相同)
C语言源程序
/******************************************************************************/
/*                                                   */
/*         led.c:  用ARM实现开关控制led并亮灭,还是有点浪费……           */
/*                                                   */
/******************************************************************************/
#include< LPC21xx.H>
#define P0_1 0x02;                                               /*P0.1*/                
/*******************************************************************************
**函数名: delay()
**描述: 软件延时
********************************************************************************/
void delay (void)  {                
   unsigned volatile long i;
   for(i=0;i<10000;i++)
   ;
}
int main(void) {
   int p01State;
   PINSEL0 = 0;           /*设置引脚为GPIO */
   IO0DIR = 0x000001;           /*将P0.0设置为输出 */
   IO0SET = 0x000001;           /*将P0.0置1,也就是让led灭 */
   while (1)  {
   p01State = IO0PIN&P0_1;           /*读取开关状态*/
           if(p01State == 0){
                   IO0CLR = 0x000001;
                   delay();
           }
           else{
                   IO0SET = 0x000001;
                   delay();
           }          
   }
}
3、LCD——ARM的Proteus实验
实验原理
ARM的P0.0口到P0.10口接LCD,P0.11接LED。每过一段时间LED状态改变,LCD显示LED的状态。
Proteus仿真电路图
C语言源程序
#include  <LPC21XX.H>
#define rs (1<<8)
#define rw (1<<9)
#define en (1<<10)
#define busy (1<<7)             //P0.7
typedef unsigned char uint8;
uint8 ledDown[]={"The LED is down!"};
uint8 ledUp[]={"The LED is up!"};
void waitLCD()                                               /*等待LCD*/
{
           IO0DIR=0xf00;
           while(1)
           {
                   IO0CLR=rs;
                   IO0SET=rw;
                   IO0SET=en;
                   if(!(IO0PIN& busy))break;
                   IO0CLR = en;
           }
           IO0DIR=0xfff;
}
void lcdOp(uint8 dat)/*送LCD控制码*/
{
           waitLCD();
           IO0CLR=rs;                  
           IO0CLR=rw;
           IO0CLR=0xff;          
           IO0SET=dat;                  
           IO0SET=en;
           IO0CLR=en;
}
void lcdData(uint8 dat)/*送LCD显示数据*/          
{
           waitLCD();
           IO0SET=rs;
           IO0CLR=rw;
           IO0CLR=0xff;          
           IO0SET=dat;                  
           IO0SET=en;
           IO0CLR=en;
}
void lcdInit(void)/*初始化LCD,DataSheet里有建议的初始化代码*/
{
           /* LCD配置为两行,5*7字体 */
           lcdOp(0x38);
           lcdOp(0x38);
           lcdOp(0x06);                            
           lcdOp(0x0E);          
           lcdOp(0x01);
           /* LCD配置为一行,5*10字体
                   lcdOp(0x34);
                   lcdOp(0x34);
                   lcdOp(0x06);                            
                   lcdOp(0x0E);          
                   lcdOp(0x01);
           */          
}
void lcdDisplay(uint8 addr,uint8 *p)/*LCD显示字符串*/
{
           lcdOp(addr);
           while(*p !='\0'){
                   lcdData(*(p++));
           }
}
void lcdClear(void)/*LCD清屏*/
{
           lcdOp(0x01);
}
void delay (void)  {                
   unsigned volatile long i,j;
   for(i=0;i<60000;i++)
   for(j=0;j<10;j++)
   ;
}
int  main(void)
{  
   lcdInit();/*初始化LCD显示*/
           IO0DIR=0xfff;//设置为输出口
           IO0CLR=0xfff;
           while (1)  {
                     IO0CLR = 0x000800;
                   lcdDisplay(0x80,ledUp);
                   delay();
                   lcdClear();
                     IO0SET = 0x000800;
                   lcdDisplay(0x80,ledDown);
                   delay();
                   lcdClear();
           }          
}
4、UART——ARM的Proteus实验
实验原理
ARM的P0.0口接LED,串口接Proteus的虚拟终端。每隔一段时间改变一次LED的状态,并且在串口上输出LED的当前状态。
Proteus仿真电路图
C语言源程序
#include< LPC21xx.H>
#include "uart.h"
#define CR 0x0D
char ledDown[]={"The LED is down!\n"};
char ledUp[]={"The LED is up!\n"};
int putchar (int ch)  {/* 向串口输出一个字符 */
   if (ch == '\n')  {
   while (!(U1LSR& 0x20));
   U1THR = CR;           a
   }
   while (!(U1LSR& 0x20));
   return (U1THR = ch);
}
void delay (void)  {                
   unsigned volatile long i,j;
   for(i=0;i<60000;i++)
   for(j=0;j<5;j++)
   ;
}
void serialPuts(char *p){/* 向串口输出字符串 */
   while (*p != '\0'){
           putchar(*p++);
   }
}
int main (void)  {
/* 开始初始化串口 */
   PINSEL0 = 0x00050000;/* 设置引脚,开串口功能 */
   U1LCR = 0x83;/* 8位数据,无效验,一个停止位 */
   U1DLL = 97;/* VPB 15MHz的时候波特率为9600 */
   U1LCR = 0x03;/* DLAB = 0 */
/* 结束初始化串口 */
   IO0DIR = 0x000001;/*将P0.0设置为输出 */
   while (1)  {
           IO0CLR = 0x000001;
           serialPuts(ledUp);
           delay();
           IO0SET = 0x000001;
           serialPuts(ledDown);
           delay();
   }
}                    
5、Eint1外部中断——ARM的Proteus实验
实验原理
ARM的P0.25接一个LED,引脚设置时连接EINT1功能,按钮触发中断。中断服务程序另LED快速闪烁。
Proteus仿真电路图
C语言源程序
#include< LPC21XX.H>
#define LEDCON 0x02000000/*LED接在P0.25上*/
typedef unsigned int uint32;
void IRQ_Eint1(void) __attribute__ ((interrupt));/*声明某函数为中断服务子程序的方法*/
uint32 times = 100;/*循环次数默认为100*/
void IRQ_Eint1(void){
   times = 5;
   while((EXTINT&0x02)!=0){
           EXTINT=0x02;             //清除EINT1中断标志
   }
   VICVectAddr=0;
}
void delay100(void)  {                
   unsigned volatile long i,j;
   for(i=0;i<10000;i++)
   for(j=0;j<times;j++)
   ;
   if(times > 100){
           times--;
   }else if(times< 100){
           times++;
   }
}
int  main(void)
           {
           IO0DIR = LEDCON;
           PINSEL0 = 0x20000000;/*引脚选中EINT1功能*/
           PINSEL1 = 0x00000000;
/*以下为中断控制部分*/                  
           VICIntSelect=0;/*全部中断设置为IRQ,若某位为1是FIQ*/
           VICIntEnable=0x00008000;/*使能EINT1,EINT为第15位*/
           VICVectCntl1=0x2F;/*0xF,15号中断*/
           VICVectAddr1=(int)IRQ_Eint1;/*设置中断服务子程序*/
           EXTINT=0x07;          
           while (1)  {
                     IO0CLR = LEDCON;
                   delay100();
                     IO0SET = LEDCON;
                   delay100();
           }
}
6、多个外部中断——ARM的Proteus实验
实验原理
ARM开启两个中断源Eint1与Eint2,分别用一个按钮来控制。在没有中断的时候两个LED都缓慢闪烁,当任何一个中断被出发的时候,对应的LED会急促闪烁,逐渐回复正常。
Proteus仿真电路图
C语言源程序
#include< LPC21XX.H>
#define LED1 0x02000000/*LED1接在P0.25上*/
#define LED0 0x01000000/*LED0接在P0.24上*/          
typedef unsigned int uint32;
void Eint1_ISR(void) __attribute__ ((interrupt));/*声明某函数为中断服务子程序的方法*/
void Eint0_ISR(void) __attribute__ ((interrupt));
uint32 times = 40;/*循环次数默认为40*/
void delay40(void)  {                
   unsigned volatile long i,j;
   for(i=0;i<10000;i++)
   for(j=0;j<times;j++)
   ;
   if(times > 40){
           times-=2;
   }else if(times< 40){
           times+=2;
   }
}
void Eint0_ISR(void){  
   times = 0;
   while(times!=40){
           IO0CLR = LED0;
           delay40();
           IO0SET = LED0;
           delay40();          
   }
   while((EXTINT&0x01)!=0){
   EXTINT=0x01;/*清除EINT0中断标志*/
   }
   VICVectAddr=0x00;
}
void Eint1_ISR(void){
   times = 0;
   while(times!=40){
           IO0CLR = LED1;
           delay40();
           IO0SET = LED1;
           delay40();          
   }
   while((EXTINT&0x02)!=0){
           EXTINT=0x02;/*清除EINT1中断标志*/
   }
   VICVectAddr=0;
}
int  main(void)
           {
           IO0DIR = LED1|LED0;
           PINSEL0 = 0x20000000;/*引脚选中EINT1功能*/
           PINSEL1 = 0x00000001;/*引脚选中EINT0功能*/
/*以下为中断控制部分*/                  
           VICIntSelect=0;/*全部中断设置为IRQ,若某位为1是FIQ*/
           VICIntEnable=0x0000C000;/*使能EINT1、0,EINT1为第15位,0为14位*/
           VICVectCntl0=0x2E;/*EINT0最高优先级*/
           VICVectAddr0=(int)Eint0_ISR;/*设置EINT0向量地址*/
           VICVectCntl1=0x2F;/*0xF,15号中断*/
           VICVectAddr1=(int)Eint1_ISR;/*设置中断服务子程序*/
           EXTINT=0x07;          
           while (1)  {/*无中断时,两灯一起缓慢闪烁*/
                     IO0CLR = LED1|LED0;
                   delay40();
                     IO0SET = LED1|LED0;
                   delay40();
           }
}
7、中断结合串口——ARM的Proteus实验
实验原理
同上多中断源实验相同,ARM开启两个中断源Eint1与Eint2,分别用一个按钮来控制。在没有中断的时候两个LED都缓慢闪烁,当任何一个中断被出发的时候,对应的LED会急促闪烁,逐渐回复正常。
此外,使用一个串口来发送当前状态,在无中断的时候发送正常状态报告,当有中断的时候,串口发送中断源。
Proteus仿真电路图
C语言源程序
文件一:main.c
#include< LPC21XX.H>
#include "uart0.h"
#define LED1 0x02000000/*LED1接在P0.25上*/
#define LED0 0x01000000/*LED0接在P0.24上*/
typedef unsigned int uint32;
void Eint1_ISR(void) __attribute__ ((interrupt));/*声明某函数为中断服务子程序的方法*/
void Eint0_ISR(void) __attribute__ ((interrupt));
uint32 times = 40;/*循环次数默认为40*/
char status[] = "Everytnig is fine.";
char eint0Str[] = "Interruption EINT0 activated!!!";
char eint1Str[] = "Interruption EINT1 activated!!!";
void delay40(void)  {                
   unsigned volatile long i,j;
   for(i=0;i<10000;i++)
   for(j=0;j<times;j++)
   ;
   if(times > 40){
           times-=2;
   }else if(times< 40){
           times+=2;
   }
}
void Eint0_ISR(void){  
   times = 0;
   while(times!=40){
           IO0CLR = LED0;
           delay40();
           IO0SET = LED0;
           delay40();
           serialPuts(eint0Str);                    
   }
   while((EXTINT&0x01)!=0){
   EXTINT=0x01;/*清除EINT0中断标志*/
   }
   VICVectAddr=0x00;
}
void Eint1_ISR(void){
   times = 0;
   while(times!=40){
           IO0CLR = LED1;
           delay40();
           IO0SET = LED1;
           delay40();
           serialPuts(eint1Str);          
   }
   while((EXTINT&0x02)!=0){
           EXTINT=0x02;/*清除EINT1中断标志*/
   }
   VICVectAddr=0;
}
int  main(void)
           {
           IO0DIR = LED1|LED0;
           PINSEL0 = 0x20000005;/*引脚选中EINT1功能,开串口UART0*/
           PINSEL1 = 0x00000001;/*引脚选中EINT0功能*/
/*以下为中断控制部分*/                  
           VICIntSelect=0;/*全部中断设置为IRQ,若某位为1是FIQ*/
           VICIntEnable=0x0000C000;/*使能EINT1、0,EINT1为第15位,0为14位*/
           VICVectCntl0=0x2E;/*EINT0最高优先级*/
           VICVectAddr0=(int)Eint0_ISR;/*设置EINT0向量地址*/
           VICVectCntl1=0x2F;/*0xF,15号中断*/
           VICVectAddr1=(int)Eint1_ISR;/*设置中断服务子程序*/
           EXTINT=0x07;
           uart0Init();          
           while (1)  {/*无中断时,两灯一起缓慢闪烁*/
                     IO0CLR = LED1|LED0;
                   delay40();
                     IO0SET = LED1|LED0;
                   delay40();
                   serialPuts(status);
           }  
}
文件二:uart0.c
#include< LPC21XX.H>
#include "uart0.h"
#define CR 0x0D
int putchar (int ch)  {/* 向串口输出一个字符 */
   if (ch == '\n')  {
   while (!(U0LSR& 0x20));
   U0THR = CR;
   }
   while (!(U0LSR& 0x20));
   return (U0THR = ch);
}
void serialPuts(char *p){/* 向串口输出字符串 */
   while (*p != '\0'){
           putchar(*p++);
   }
   putchar('\n');
}
void uart0Init(void){
   U0LCR = 0x83;/* 8位数据,无效验,一个停止位 */
   U0DLL = 97;/* VPB 15MHz的时候波特率为9600 */
   U0LCR = 0x03;/* DLAB = 0 */
}
8、定时器——ARM的Proteus实验
实验原理
ARM的定时器实验,定时改变LED的状态。
Proteus仿真电路图
C语言源程序
#include< LPC21xx.H>
#define LED 0x000001
typedef unsigned int uint32;
typedef unsigned char uint8;
void timer0_ISR (void) __attribute__ ((interrupt));
uint8 timer0Times = 0;
void timer0Init (void) {
   T0MR0 = 119999;/*匹配寄存器,120000-1,12000000为1秒*/
   T0MCR = 3;/*产生中断,重置TC*/
   T0TCR = 1;/*使能定时计数器0*/
   VICVectAddr0 = (unsigned long)timer0_ISR;      
   VICVectCntl0 = 0x20 | 4;/*定时器计数器0为4号中断*/
   VICIntEnable = 0x00000010;/*开定时计数器0中断*/
}
void timer0_ISR (void) {
           timer0Times++;
           uint32  i;
           if(timer0Times == 10){
                   i=IO0SET;                 //读出当前LED2控制值
                   if((i&LED)==0){
                             IO0SET=LED;
                   }else{
                             IO0CLR=LED;
                   }
                   timer0Times = 0;
           }
   T0IR = 1;/*清除定时器0中断*/
   VICVectAddr = 0;                
}
int main(void) {
   PINSEL0 = 0;/*设置引脚为GPIO */
   IO0DIR = LED;/*将P0.0设置为输出 */
   IO0SET = LED;/*将P0.0置1,也就是让led灭 */
   timer0Init();
   while (1)  {
   }
}
9、SPI通信——ARM的Proteus实验
实验原理
使用SPI协议,利用ARM控制数码显示管显示1到F,用串口检验发送的数据是否正确。
Proteus仿真电路图
C语言源程序
下面是主程序文件,串口部分的程序代码与“中断结合串口”相同,所以省略。
#include< LPC21XX.H>
#include "uart0.h"
#define   HC595_CS   0x00000100/*P0.8口为74HC595的片选*/
typedef unsigned int uint32;
typedef unsigned char uint8;
char status[] = "Everytnig is fine.";
uint8 const DISP_TAB[16]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,
0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};
uint8 rcv_data;
void delay(void)  {                
   unsigned volatile long i,j;
   for(i=0;i<10000;i++)
   for(j=0;j<30;j++)
   ;
}
void spiInit(void){
   S0SPCCR=0x52;         //设置SPI时钟分频
   S0SPCR=0x30;         //设置SPI接口模式
}
uint8 spiChar(uint8 data){
   IO0CLR=HC595_CS;                     //片选
   S0SPDR=data;
   while(0==(S0SPSR&0x80));               //等待SPIF置位,即等待数据发送完毕
   IO0SET=HC595_CS;
   return(S0SPDR);
}
int  main(void){
   uint8 i;
   PINSEL0 = 0x00005505;/*引脚开串口SPI、UART0*/          
   IO0DIR=HC595_CS;
   spiInit();/*初始化SPI接口*/
   uart0Init();
   while(1){
   for (i=0;i<16;i++) {
                   if(i<10){putchar(i+'0');}
                             else{putchar(i+7+'0');}
                   rcv_data=spiChar(DISP_TAB[ i]);/*发送显示数据*/
                   delay();
   }
           serialPuts(status);
   }
}
[ i]
10、SPI通信(多从设备)——ARM的Proteus实验
实验原理
使用SPI协议,利用ARM控制数码显示管1显示1到F,数码显示管2则从F到1倒计数,数码显示管则一直显示0。该连接方法使用片选来激活不同的SPI从设备(HC595)。
Proteus仿真电路图
C语言源程序
下面是主程序文件,串口部分的程序代码与“中断结合串口”相同,所以省略。
#include< LPC21XX.H>
#include "uart0.h"
#define   HC595_CS     0x00000100/*P0.8口为第一个74HC595的片选*/
#define   HC595_CS2   0x00000200/*P0.9口为第二个74HC595的片选*/
#define   HC595_CS3   0x00000400/*P0.10口为第三个74HC595的片选*/
typedef unsigned int uint32;
typedef unsigned char uint8;
char status[] = "Everytnig is fine.";
uint8 const DISP_TAB[16]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,
0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};
uint8 rcv_data;
void delay(void)  {                
   unsigned volatile long i,j;
   for(i=0;i<10000;i++)
   for(j=0;j<30;j++)
   ;
}
void spiInit(void){
   S0SPCCR=0x52;/*设置SPI时钟分频*/
   S0SPCR=0x30;/*设置SPI接口模式*/
}
uint8 spiChar(uint8 data){
   IO0CLR=HC595_CS;/*SPI1片选*/
   S0SPDR=data;
   while(0==(S0SPSR&0x80));/*等待SPIF置位,即等待数据发送完毕*/
   IO0SET=HC595_CS;
   return(S0SPDR);
}
uint8 spi2Char(uint8 data){
   IO0CLR=HC595_CS2;/*SPI2片选*/
   S0SPDR=data;
   while(0==(S0SPSR&0x80));
   IO0SET=HC595_CS2;
   return(S0SPDR);
}
uint8 spi3Char(uint8 data){
   IO0CLR=HC595_CS3;/*SPI3片选*/
   S0SPDR=data;
   while(0==(S0SPSR&0x80));
   IO0SET=HC595_CS3;
   return(S0SPDR);
}
int  main(void){
   uint8 i;
   PINSEL0 = 0x00005505;/*引脚开SPI、UART0*/          
   IO0DIR=HC595_CS|HC595_CS2|HC595_CS3;
   spiInit();/*初始化SPI接口*/
   uart0Init();
   while(1){
   for (i=0;i<16;i++) {
                   if(i<10){putchar(i+'0');}
                             else{putchar(i+7+'0');}
                   rcv_data=spiChar(DISP_TAB[ i]);/*发送显示数据到数码显示管1*/
                   rcv_data=spi2Char(DISP_TAB[15-i]);/*数码显示管2*/
                   rcv_data=spi3Char(DISP_TAB[0]);/*数码显示管2*/
                   delay();
   }
           serialPuts(status);
   }
}
[ i]
11、ADC数模转换——ARM的Proteus实验
实验原理
使用ARM微处理器内置的AD转换,将电压值转换为数字量后直接输出到串口UART0。
Proteus仿真电路图
C语言源程序
main.c
#include< LPC21XX.H>
#include "uart0.h"
typedef unsigned int uint32;
void delay(void)  {                
   unsigned volatile long i,j;
   for(i=0;i<10000;i++)
   for(j=0;j<50;j++)
   ;
}
void adcRead (void) {              
   unsigned int val;
   ADCR |= 0x01000000;/* 开始AD转换 */
   do {
   val = ADDR;/* 读取AD转换数据寄存器 */
   } while ((val& 0x80000000) == 0);/* 等待AD转换结束 */
   ADCR& = ~0x01000000;/* 结束AD转换 */
   val = (val >> 6)& 0x03FF;/* 设置数据格式并且按照16进制输出 */
   putstr ("\nAIN0 Result = 0x");      
   puthex((val >> 8)& 0x0F);          
   puthex((val >> 4)& 0x0F);          
   puthex (val& 0x0F);              
}
int  main(void)
           {
           ADCR   = 0x002E0401;/* Setup A/D: 10-bit AIN0 @ 3MHz */
           PINSEL0 = 0x20000005;/*引脚选中EINT1功能,开串口UART0*/
           PINSEL1 = 0x00000001;/*引脚选中EINT0功能*/
           uart0Init();          
           while (1)  {          
                   adcRead();
                   delay();
           }  
}
uart0.c
#include< LPC21XX.H>
#include "uart0.h"
#define CR 0x0D
int putchar (int ch)  {/* 向串口输出一个字符 */
   if (ch == '\n')  {
   while (!(U0LSR& 0x20));
   U0THR = CR;
   }
   while (!(U0LSR& 0x20));
   return (U0THR = ch);
}
void serialPuts(char *p){/* 向串口输出字符串 */
   while (*p != '\0'){
           putchar(*p++);
   }
   putchar('\n');
}
void uart0Init(void){
   U0LCR = 0x83;/* 8位数据,无效验,一个停止位 */
   U0DLL = 97;/* VPB 15MHz的时候波特率为9600 */
   U0LCR = 0x03;/* DLAB = 0 */
}                    
void puthex (int hex) {/* Write Hex Digit to Serial Port  */
   if (hex > 9) putchar('A' + (hex - 10));
   else       putchar('0' +  hex);
}
void putstr (char *p) {/* Write string */
   while (*p) {
   putchar(*p++);
   }
}


完整的Word格式文档51黑下载地址:
菜鸟的ARM学习笔记proteus仿真.zip(183.92 KB, 下载次数: 115)
ID:616451发表于 2019-9-25 23:33来自手机|显示全部楼层
兄弟,你这个第三个我按照你的程序写,为啥写出来无法输出,而且只会亮屏
ID:616451发表于 2019-9-26 09:36|显示全部楼层
而且会报错“[HD44780] Controller received data whilst busy. [LCD1]
ID:1077325发表于 2023-5-13 21:59|显示全部楼层
楼主你好,请问代码中的uart0.h文件哪里可以获得?
ID:1077512发表于 2023-5-15 00:00|显示全部楼层
SPI通信里的uart0.h文件是自己写的吗?

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

Powered by 单片机教程网