求基于LPC2103的四相步进电机程序

求基于LPC2103的四相步进电机程序,第1张

#define IOCON 8006H

#define IOA 8000H

#define IOB 8002H

#define IOC 8004H

unsigned char table1[8]={0x02,0x06,0x04,0x0c,0x08,0x09,0x01,0x03}

unsigned char table2[8]={0x03,0x01,0x09,0x08,0x0c,0x04,0x06,0x02}

void outp(unsigned int addr, char data)

// Write a byte to the specified I/O port

{ __asm

{ mov dx, addr

mov al, data

out dx, al

}

}

char inp(unsigned int addr)

// Read a byte from the specified I/O port

{ char result

__asm

{ mov dx, addr

in al, dx

mov result, al

}

return result

}

void delay()

{

int i,j

for(i=10i>0i--)

for(j=0j<1j++){}

}

void main(void)

{

unsigned char i,tmp

outp(IOCON,0x90)

i=0

while(1){

i=inp(IOA)

if(i==0xfd)

while(1){

for(tmp=0tmp<8tmp++){

outp(IOB,table2[tmp])

i=inp(IOA)

if(i==0xfe||i==0xfb)break

delay()

}

if(i==0xfe||i==0xfb)break

}

if(i==0xfe)

while(1){

for(tmp=0tmp<8tmp++){

outp(IOB,table1[tmp])

i=inp(IOA)

if(i==0xfd||i==0xfb)break

delay()

}

if(i==0xfd||i==0xfb)break

}

if(i==0xfb)outp(IOB,0xf0)

}

}

一下来自我的空间http://hi.baidu.com/ch314156/blog

注意要设定选项,不然中断向量表不位于地址0出,也就无法进入中断例程,具体设定方法是:Options for Target'???'->Linker->选中"Use Memory Layout from Target Dialog"

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

//非向量外部中断C例程

//P0.16做键盘输入,P0.18做LED输出

#include<LPC2103.H>

#define LED 1<<18

void __irq WaiBuZhongDuan(void) // 注意要加“__irq”,告诉编译器,

{ //这是中断例程

if((IOSET&LED)==0) IOSET=LED

else IOCLR=LED//将P0.0取反

EXTINT=0X01//清除中断标志,写1清0

VICVectAddr=0//清0,通知VIC中断结束

}

int main(void)

{

PINSEL1=0X1//P0.16选为外部中断0引脚输入

IODIR=LED//P0.18作为LED输出

EXTMODE=0X01//边沿触发

VICDefVectAddr=(int)WaiBuZhongDuan//填入中断例程的地址

VICIntEnable=1<<14//使能EINT0中断

while(1)

}

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

PROTEUS仿真见下:

硬件仿真:

补充说明:程序中没有区分IRQ或FIQ,因为VICIntSelect默认为0即所有中断源都是IRQ。

如果中断不能进入,查看一下CPSR中的I位,如果是1,说明CPSR中断标志禁止中断,所以要将I清0,解决办法是利用一个软件中断,进入管理模式,将SPSR的I清0,返回前将SPSR复制到CPSR中。具体做法有待以后解决。本来是想用内嵌汇编的,但是考虑到用户模式不能对CPSR修改。或者修改一下启动代码。

VICDefVectAddr是非向量IRQ的中断例程地址(与此相似的16个向量IRQ的中断例程地址VICVectAddr0~15),中断触发后,VICDefVectAddr(同样,如果是向量IRQ,相应的VICDefVectAddr0~15)中的值自动进入VICVectAddr,所以PC指向VICVectAddr后就进入相应的中断例程。

那么PC为什么会指向VICVectAddr呢?与C51相似的是,ARM的IRQ触发后,PC会跳到0x00000018地址处,查看Startup里的异常向量表,在地址0x00000018处有这样一条指令: LDR PC, [PC, #-0x0FF0],计算一下 0x00000018+8-0x0FF0=0xFFFFF030,(+8是因为三级流水线),0xFFFFF030就是VICVectAddr的地址。

观察一下异常向量表,和C51的中断向量表比较一下,是不是有相似之处:

ARM:

Vectors LDR PC, Reset_Addr 0x00000000复位

LDR PC, Undef_Addr 0x00000004未定义异常

LDR PC, SWI_Addr 0x00000008软件中断

LDR PC, PAbt_Addr 0x0000000C预取指中止

LDR PC, DAbt_Addr 0x00000010数据中止

NOP 0x00000014保留

LDR PC, IRQ_Addr

LDR PC, [PC, #-0x0FF0] 0x00000018中断

LDR PC, FIQ_Addr 0x0000001C快速中断

C51:

ORG 0003H

SJMP INT0

ORG 000BH

SJMP TIME0

ORG 0013H

SJMP INT1

ORG 001BH

SJMP TIME1

ORG 0023H

SJMP SERIAL

VICIntEnable=1<<14是因为外部中断0的编号为14。

“__irq”如果不写,编译器无法正常处理此中断例程,经测试,如果没有,中断例程不能返回正常,具体原因:若不加“__irq”,编译器把此程序看作普通子程序,返回指令是BX RL,若加“__irq”,编译器把此程序看作中断例程,返回指令是SUBS PC,R14,#4,这才是中断返回的正确指令。

EXTINT是外部中断的中断标志位,写1才能清0,写0无效,硬件仿真证明:如果不清0,中断例程将无限循环。顺便说一句:PROTEUS的虚拟仿真结果和事实(硬件仿真)有差异,比如对EXTINT、EXTMODE,VICVectAddr=0没有真实表现,KEIL的软件仿真效果和事实符合的很好。

经测定:如果没有VICVectAddr=0这一句代码,程序将不会第二次进入中断例程。

详细看我空间

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

//LPC2103(主机)与AT24C02(从机)的I2C传输

//功能:将A数组中的n各字节写入AT24C02,再从AT24C02里读回数据到B数组

#include<lpc2103.h>

//I2C控制寄存器的相应位:

#define AA 1<<2 //应答位

#define SI 1<<3 //中断标志

#define STO 1<<4 //停止标志

#define STA 1<<5 //起始标志

#define I2EN 1<<6 //I2C使能

#define AT24C02_device_address 0XA0

#define u8 unsigned char

//函数声明

void initialize(void)

void send(u8 device_address,u8 *A,u8 memory_address,u8 number)

void start(void)

void start_repeat(void)

void stop(void)

void send_slave_address(u8 device_address)

void send_data(u8 byte)

void receive(u8 device_address,u8 memory_address,u8 *B,u8 number)

int receive_data(u8)

void delay(int k)

u8 A[10]={0,1,2,3,4,5,6,7,8,9},B[10]={0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99}

int main()

{

initialize()//I2C接口初始化

//向器件地址为AT24C02_device_address的器件发送字节,源地址为A,目标地址(AT24C02的数据指针)为0,字节数:10个

send(AT24C02_device_address,A,0,10)

delay(100000)//延时,手册上说两次写间隔至少5ms

//向器件地址为AT24C02_device_address的器件接收字节,源地址(AT24C02的数据指针)为1,目标地址为B,字节数:6个

receive(AT24C02_device_address,1,B,6)

while(1)

}

void initialize() //I2C接口初始化

{

I2C0CONCLR=AA|SI|STA|I2EN// I2C0CO所有位清0

I2C0CONSET=I2EN//I2C接口使能

PINSEL0=0X50//选择P0.2为SCL0,P0.3为SDA0

I2C0SCLH=15

I2C0SCLL=15//位频率=PCLK/(I2C0SCLH+I2C0SCLL)

}

//向器件地址为device_address的器件发送字节,源地址为A,目标地址为memory_address,字节数:number个

void send(u8 device_address,u8 *A,u8 memory_address,u8 number)

{

unsigned char i

start()//起始信号

send_slave_address(AT24C02_device_address)//发送器件地址+写

send_data(memory_address)// 发送24C02片内的数据地址

for(i=0i<numberi++) //发送number个字节

{

send_data(A[i])//发送字节A[i]

}

stop()//停止信号

}

void start() //起始信号

{

I2C0CONSET=STA//发送起始信号

I2C0CONCLR=SI//中断标志清0

while(I2C0STAT!=0x08)//发送起始信号完毕

I2C0CONCLR=STA//关闭起始信号

}

void start_repeat() //“重复起始”信号

{

I2C0CONSET=STA//发送起始信号

I2C0CONCLR=SI//中断标志清0

while(I2C0STAT!=0x10)//发送“重复起始”信号完毕

I2C0CONCLR=STA//关闭起始信号

}

void stop() //发送停止信号

{

I2C0CONSET=STO//发送停止信号

I2C0CONCLR=SI//中断标志清0

}

void send_slave_address(u8 device_address) //发送器件地址device_address

{

I2C0DAT=device_address//发送器件地址

I2C0CONCLR=SI//中断标志清0

if((device_address&0x01)==0)while(I2C0STAT!=0x18)//如果是写 *** 作,等待:发送地址和收到应答

else while(I2C0STAT!=0x40)//如果是读 *** 作,等待:发送地址和收到应答

}

void send_data(u8 byte) //发送一个字节

{

I2C0DAT=byte//发送一个字节

I2C0CONCLR=SI//中断标志清0

while(I2C0STAT!=0x28)//等待:发送字节和收到应答

}

//向器件地址为device_address的器件接收字节,源地址为memory_address,目标地址为B,字节数:number个

void receive(u8 device_address,u8 memory_address,u8 *B,u8 number)

{

unsigned char i

start()//发送起始信号

send_slave_address(device_address)//发送器件地址

send_data(memory_address)//发送器件的片内地址

start_repeat()//发送“重复起始”信号

send_slave_address(device_address|1)//发送器件地址

for(i=0i<numberi++) //发送number个字节

{ //将收到的字节放入B数组,i==(number-1)表示是否为最后一个字节

B[i]=receive_data(i==(number-1))

}

stop()//发送停止信号

}

int receive_data(u8 last) //接收一个字节,发送应答或非应答

{

if(last) //如果是最后一个字节

{

I2C0CONCLR=AA//发送一个非应答

I2C0CONCLR=SI//中断标志清0

while(I2C0STAT!=0x58)//等待:接收数据直接和发出非ACK

}

else

{

I2C0CONSET=AA//发送一个应答位

I2C0CONCLR=SI//中断标志清0

while(I2C0STAT!=0x50)//等待:接收数据直接和ACK

}

return (I2C0DAT)//返回接收的字节

}

void delay(int k) //延时

{ while(k--)}

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


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/11831682.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-19
下一篇 2023-05-19

发表评论

登录后才能评论

评论列表(0条)

保存