最近学习了ARM9基础程序的设计,记录下所学心得,希望对初学者提供一些帮助。学习ARM程序要注意方法,先去芯片手册的相应模块部分的结构原理框图,搞清楚所使用的模块的基本原理,然后根据框图搞清楚需要设置哪些对应的寄存器,再根据时序图搞明白相应寄存器应该怎样设置,再接着理清楚你所写程序的大概流程,最后就可以动手写程序了。
如果把流程理清楚了,你的程序基本上已经成功一半了。
我使用的是S3C2440 ARM芯片,
一 LED流水灯程序
流程:
1,设置端口控制寄存器将LED对应端口设为输出模式 (GPxCON)。
2,向端口对应的数据寄存器发送数据(GPxDAT)。
实现:
//这段宏定义了使对应LED亮应该送的数据
#define LED1_ON ~(1<<5)
#define LED2_ON ~(1<<6)
#define LED3_ON ~ (1<<7)
#define LED4_ON ~(1<<8)
#define LED1_OFF (1<<5)
#define LED2_OFF (1<<6)
#define LED3_OFF (1<<7)
#define LED4_OFF (1<<8)
//LED初始化函数,设置GPBCON为输出端口,并往端口送数据,使所有LED处于灭的状态
void LEDInit()
{
rGPBCON |= (1<<10) | (1<<12) | (1<<14) | (1<<16);
rGPBDAT |= (LED1_OFF | LED2_OFF |LED3_OFF | LED4_OFF);
}
//LED轮流闪亮函数,先点亮对应LED,然后延时,再关闭
void LEDRun()
{
rGPBDAT &= LED1_ON;
delay(1000);
rGPBDAT |= LED1_OFF;
rGPBDAT &= LED2_ON;
delay(1000);
rGPBDAT |= LED2_OFF;
rGPBDAT &= LED3_ON;
delay(1000);
rGPBDAT |= LED3_OFF;
rGPBDAT &= LED4_ON;
delay(1000);
rGPBDAT |= LED4_OFF;
}
二 按键中断程序
流程:
中断处理流程
1 中断控制器汇集各类外设发出的中断信号,然后告诉CPU
2 CPU保存当前程序的运行环境,然后调用中断服务程序来处理中断
3 在ISR中通过读取中断控制寄存器,外设相关的寄存器来识别是哪个中断,并进行相应的处理
4 清楚中断:通过读写相关的中断控制寄存器和外设相关寄存器来实现
5 最好恢复被中断程序的环境,继续执行
按键中断程序流程:
初始化
1 设置按键对应的端口为中断(GPxCON)
2 设置中断程序入口
3 清外部中断挂起寄存器EINITPEND和挂起寄存器INTPND,SRCPND,防止原有干扰
4 设置电平触发方式(EXTINITn)
5 关闭外部中断ENTMASK和INTMASK对中断的屏蔽
中断程序
6清挂起寄存器INTPND,SRCPND,防止反复响应该中断
7 通过判断rEINITPEND相应的位来确定是哪一个按键产生的中断,然后执行相应的程序,并清除rEINITPEND相应的位,防止反复的响应
程序:
static void __irq KeyHander();//声明中断处理函数
//按键初始化函数
void KeyInit()
{
MMU_Init();
rGPGCON |= (1<<1 | 1<<7 | 1<<11 | 1<<13 );//设置GPGCON相应端口为中断
pISR_EINT8_23 = (U32)KeyHander;//设置中断程序入口
rEINTPEND |= (1<<8 | 1<<11 | 1<<13 | 1<<14); //清外部中断挂起寄存器,防止干扰
ClearPending(BIT_EINT8_23);
rEINTMASK &= ~(1<<8 | 1<<11 | 1<<13 | 1<<14); //打开外部中断屏蔽器
//rEXTINIT1为设置中断触发方式寄存器,因为其默认是低电平触发,所以不需要设置
EnableIrq(BIT_EINT8_23);//使能中断,其实是打开MASK
}
//按键响应函数
void KeyHander()
{
ClearPending(BIT_EINT8_23);//清中断挂起寄存器包括SRCPND INTPND
if(rEINTPEND & 1<<8)//通过外部中断挂起寄存器判断是哪个按键请求中断
{
rEINTPEND |= 1<<8;//清外部中断挂起寄存器,防止反复中断
LightLed(1);
}
if(rEINTPEND & 1<<11)
{
rEINTPEND |= 1<<11;
LightLed(2);
}
if(rEINTPEND & 1<<13)
{
rEINTPEND |= 1<<13;
LightLed(3);
}
if(rEINTPEND & 1<<14)
{
rEINTPEND |= 1<<14;
LightLed(4);
}
}
三 定时器中断程序
CPU时钟设置流程
1 设置MPLLCON寄存器设置FCLK
2 设置CLKDIVN寄存器设置FCLK:HCLK:PCLK的值
时钟设置流程
初始化
1 设置分频值TCFG0 TCFG1
2 设置定时器计数值 TCNTB0
3 设置中断程序入口,清挂起寄存器和关闭MASK屏蔽
4 更新TCTNB0和TCMTB0的值 TCCON
5 将TCCON清0,否则就会cpu就会一直在更新
启动定时器
6 启动定时器,TCCON
中断函数
清挂起寄存器,执行响应代码
void SetSysClk()//FCLK=405MHZ FCLK:HCLK:PCLK=1:4:8
{
rMPLLCON = 0;
rMPLLCON |= (0x3f<<12 | 2<<4 | 2<<0);//设置FCLK的值
rCLKDIVN |= (1<<2 | 1<<0);//设置FCLK:HCLK:PCLK的比值
//LOCKTIME不需要设置,如没设置,系统将自动选择LOCKTIME
}
void Timer0Init()//PCLK=50MHZ
{
rTCFG0 = 49;
rTCFG1 |= 2; //CLK=62500HZ
//TCFG0 TCFG1设置定时器预分频值和分配值 然后得出定时器0频率:FCLK/(49+1)/16
rTCNTB0 = 62500;
//TCNTB0设置定时器的计数寄存器
ClearPending(BIT_TIMER0);//清除计数器0中断挂起寄存器
pISR_TIMER0 = (U32)Timer0Handle;
EnableIrq(BIT_TIMER0);//打开MASK对定时器0的屏蔽
rTCON |=(1<<1); //更新TCNTB0 和 TCMTB0的值
rTCON =0; //将TCON的值清0,注这一步很重要,如没有,定时器将一直更新TCNTB0和TCMTB0的值导致无法启动
rTCON |= (1<<3 | 1<<0);//启动定时器0,并设置为自动装载
}
static void __irq Timer0Handle()
{
ClearPending(BIT_TIMER0);//清除TIMER0中断挂起寄存器,防止其反复相应
LedRun();
}
四,串口发送程序
流程:
初始化
1 设置相应的GPIO端口为串口输出端口
2 设置串口发生数据格式ULCONn
3 设置接收和发生方式 ULCONn
4 设置波特率rUBRDIVn
发送数据
5 等待发送缓冲区为空 rUTRSTATn
6 向发生数据寄存器写数据 UTXHn
程序:
void UartInit(int num, int buad)
{
int i;
switch(num)
{
case 0:
rGPHCON |= (1<<5 | 1<<7);//设置GPH端口为串口
rULCON0 = 0x03;//设置数据格式为8位数据
rUCON0 = (1<<0 | 1<<2); //设置接收和发送为查询模式
rUBRDIV0 = ((int)PCLK/(16*buad) - 1);//设置波特率
break;
case 1:
rGPHCON |= (1<<9 | 1<<11);
rUBRDIV1 = ((int)PCLK/(16*buad) - 1);
rULCON1 = 0x03;
rUCON1 = (1<<0 | 1<<2);
break;
case 2:
rGPHCON |= (1<<13| 1<<15);
rUBRDIV2 = ((int)PCLK/(16*buad) - 1);
rULCON2 = 0x03;
rUCON2 = (1<<0 | 1<<2);
break;
default:
break;
}
for( i=0; i != 100; ++i);//延时,使设置生效
}
void UartPrintf(char *fmt, ...)
{
va_list ap;
char string[256];
//将不定参数格式化成字符串string
va_start(ap, fmt);
vsprintf(string, fmt, ap);
UartSendString(string);
va_end(ap);
}
void UartSendString(char *str)
{
while(*str)
Uart_SendByte(*str++);
}
void UartSendByte(char byte)
{
switch(whichUart)
{
case 0:
while( ! (rUTRSTAT0 & 0x02));//等待发生区为空
WrUTXH0(byte);
break;
case 1:
while( ! (rUTRSTAT1 & 0x02));
WrUTXH1(byte);
break;
case 2:
while( ! (rUTRSTAT2 & 0x02));
WrUTXH2(byte);
break;
default:
break;
}
}
五,ADC转换程序
流程
初始化
1 设置转换通道和转换频率ADCCONn
2 清相应的中断挂起寄存器,设置中断入口程序,取消MASK屏蔽
启动
3 设置ADCCONn相应的位启动转换
中断服务程序
4通过SUBSRCPND判断是不是普通的ADC转换
5 清SUBSRCPND相应的位
6 读取转换值 ADCDATn
程序
void ADCInit()
{
int channel = 0, preScaler = 50000000/ADCFRE - 1;
rADCCON = (channel<<3) | (preScaler<<6) | (1<<14);//设置ADC通道和预分频值
Delay(100);
pISR_ADC = (U32)ADCHandle;//设置中断向量表
ClearPending(BIT_ADC);//清挂起寄存器
rSUBSRCPND &= (1<<10);//清子中断挂起寄存器
EnableIrq(BIT_ADC);//使能ADC中断,实际是关闭INTMSK对ADC的屏蔽
rINTSUBMSK &= (0<<10);//关闭子中断对ADC_S的屏蔽
rADCCON |= 1;//开始转换
}
static void __irq ADCHandle()
{
int ADCValue;
ClearPending(BIT_ADC);
if(rSUBSRCPND & (1<<10))//判断是不是有ADC普通转换产生的中断
{
rSUBSRCPND &= (1<<10);
ADCValue = (rADCDAT0 & 0x3FF);//读取转换值
Uart_Printf("/n ADC convert value is %d/n", ADCValue);
rADCCON |= 1;//开始转换
}
}
六,触摸屏程序
流程:
初始化
1 设置采样延时和分频值ADCDLY ADCCON
2 中断相关设置
3 设置触摸屏AD转换为等待中断模式 ADCTSC
中断服务函数
4清相关挂起寄存器
5设置转换模式,一般为连续x,y转换
6 启动转换
7 转换完成后读取x y坐标ADCDAT0 ADCDAT1
8 设置触摸屏AD转换为等待中断模式,设置等待弹起中断ADCTSC
9 弹起中断发生后,设置触摸屏转换为等待中断模式,等待下一次触笔按下rADCTSC
程序
void TouchPendInit()
{
ADCInit();
rADCTSC = 0xd3;//设置为等待中断模式
rSUBSRCPND |= (1<<9);//清ADC_TC挂起寄存器
rINTSUBMSK &= ~(1<<9);//ADC_TC屏蔽
}
void ADCInit()
{
int channel = 0, preScaler = 50000000/ADCFRE - 1;
rADCDLY=50000; //设置触摸屏转换延时,这个延时需要设置,否则数值不对
//rADCCON = (channel<<3) | (preScaler<<6) | (1<<14);//设置ADC通道和预分频值
rADCCON=(1<<14) | (preScaler<<6);
Delay(100);
pISR_ADC = (U32)ADCHandle;//设置中断向量表
ClearPending(BIT_ADC);//清挂起寄存器
rSUBSRCPND |= (1<<10);//清子中断挂起寄存器
EnableIrq(BIT_ADC);//使能ADC中断,实际是关闭INTMSK对ADC的屏蔽
rINTSUBMSK &= ~(1<<10);//关闭子中断对ADC_S的屏蔽*/
}
static void __irq ADCHandle()
{
int xADCValue, yADCValue;
ClearPending(BIT_ADC);
if(rSUBSRCPND & (1<<9))
{
rSUBSRCPND |= (1<<9);
rADCTSC |= (1<<2);//设置转换模式,X,Y连续自动转换
rADCCON |= 1;//开始转换
}
if(rSUBSRCPND & (1<<10))//判断是不是有ADC普通转换产生的中断
{
rSUBSRCPND |= (1<<10);
xADCValue = (rADCDAT0 & 0x3FF);//读取转换值
yADCValue = (rADCDAT1 & 0x3FF);
Uart_Printf("/n x=%d, y=%d/n", xADCValue, yADCValue);
rADCTSC = 0xd3;//设置为等待中断模式
rADCTSC |= (1<<8);//检测弹起中断
//等待弹起
while(1)
{
if(rSUBSRCPND & (1<<9))
{
rSUBSRCPND |= (1<<9);
rADCTSC = 0xd3;
break;
}
}
}
}
七,LCD程序
流程:
初始化
1 端口初始化,设置相应的端口为LCD端口
2 显示模式初始化,设置帧同步信号,行同步信号,屏幕大小,像素显示模式等等
3 帧缓冲初始化,设置帧缓冲的起始地址,中止地址,虚拟屏宽等等
开始输出
4 启动输出
5 往帧缓冲写入要显示的图像数据
程序:
#define LCD_WIDTH 240
#define LCD_HEIGHT 320
#define LCD_PIXCLOCK 4
#define LCD_RIGHT_MARGIN 39
#define LCD_LEFT_MARGIN 16
#define LCD_HSYNC_LEN 5
#define LCD_UPPER_MARGIN 1
#define LCD_LOWER_MARGIN 5
#define LCD_VSYNC_LEN 1
static unsigned short lcdbuffer[LCD_WIDTH][LCD_HEIGHT];//定义显存
void LCDPortInit()
{
rGPCCON = 0xaaaa00a8;//设置GPC端口为VCLK,VLINE,VFRAME VD输出
rGPCUP = 0xffff;
rGPDCON = 0xaaaaaaaa;//设置GPD端口为VD输出
rGPDUP = 0xffff;//禁止上拉
}
void LCDInit()
{
U32 bufferaddr =(U32)lcdbuffer;
LCDPortInit();
rLCDCON1 = (LCD_PIXCLOCK<<8) | (3<<5) | (0xC<<1);//设置VCLK时钟,显示模式为TFT,像格式素模式为16位
rLCDCON2 = (LCD_UPPER_MARGIN<<24) | ((LCD_HEIGHT-1)<<14) | (LCD_LOWER_MARGIN<<6) | (LCD_VSYNC_LEN<<0);//设置帧同步信号发生后无效的时钟,LCD高度,下一帧同步信号发生前的无效时钟,行同步信号的秒冲宽度
rLCDCON3 = (LCD_LEFT_MARGIN<<19) | ((LCD_WIDTH-1)<<8) | (LCD_RIGHT_MARGIN<<0);//设置行同步信号发生后无效的时钟,LCD宽度,下一个同步行同步信号发生前的无效时钟宽度
rLCDCON4 = (LCD_HSYNC_LEN<<0);//设置行同步信号时钟脉冲宽度
rLCDCON5 = (1<<11);//设置像素格式为5:6::5
rLCDSADDR1 = ((bufferaddr>>22)<<21) | (((bufferaddr>>1)&0x1fffff)<<0);//设置显存的起始地址
rLCDSADDR2 = ((bufferaddr + LCD_WIDTH*LCD_WIDTH*2)>>1)&0x1ffff;//设置显存的末端地址
rLCDSADDR3 = LCD_WIDTH; //设置虚拟屏幕宽度即为实际宽度
rLCDCON1 |= 1; //开始输出
}
void LCDDisplay()
{
LCDSubDisplay((0x1f<<11) | (0x00<<5) | (0x00)); //red
delay(100000);
LCDSubDisplay((0x00<<11) | (0x3f<<5) | (0x00)); //green
delay(100000);
LCDSubDisplay((0x00<<11) | (0x00<<5) | (0x1f)); //blue
delay(100000);
}
void LCDSubDisplay(U16 c)
{
unsigned int x ,y ;
for( x=0; x }
上一篇:ARM9(S3C2440)时钟与定时器
下一篇:ARM汇编语言与C/C++的混合编程
推荐阅读最新更新时间:2024-11-13 10:22
推荐帖子
- 如何使用STR71x的软件库在IAR中进行应用开发
- 由于公司使用软件的限制,我使用的压缩软件是7zip,对这个软件使用不熟悉,压缩出来的文件有问题,请大家下载下面的RAR压缩文件。相关链接:https://bbs.eeworld.com.cn/upfiles/img/20074/200743103855769.zip如何使用STR71x的软件库在IAR中进行应用开发相关链接:https://bbs.eeworld.com.cn/upfiles/img/20074/20074310416254.zip第二部分相关链接:h
- icedog stm32/stm8
- FPGA的最大灌电流是多少
- 请问EP2C8Q208最大允许灌电流是多少啊FPGA的最大灌电流是多少片子使用的是LVTTL电平,那么LZ可以查一下LVTTL电平能支持的最大藻电流就行了。。期待哪个给出答案。。。。回复楼主白丁的帖子应该是4毫安!这样的问题应该去看器件手册,必须以器件手册为准。这也太小了把回复板凳eeleader的帖子对应灌电流来说应该是很大的了 资料都是网上公开的,与其在论坛上问需等好几个回合,顺手查一下岂不是轻松得多?再说这类问题即使问到了也不能轻信,应养成非亲手查到
- 白丁 FPGA/CPLD
- MSP430控制的DDS输出波形为正弦波和方波c程序
- //***************************************************////子程序说明////***************************************************////函数1:ad9850_reset()//复位ad9850,之后为并口写入模式//函数2:ad9850_reset_serial()//复位ad9850,之后为串口写入模式/
- Aguilera 微控制器 MCU
- 【T叔藏书阁】锁相技术相关专辑
- 锁相技术相关专辑38册209M.part1锁相技术相关专辑38册209M.part2锁相技术相关专辑38册209M.part3锁相技术相关专辑38册209M.part4锁相技术相关专辑38册209M.part5锁相技术相关专辑38册209M.part6【T叔藏书阁】锁相技术相关专辑:loveliness:
- tyw 下载中心专版
- ATmega8 串口问题
- 我把ATmega8的TX和AT89C52单片机的TX线与后,出现AT89C52发送出的信号被拉高,有遇到这样的情况的吗?如何解决?注:原来使用的是AT89C52,现想改用ATmega8,所以必须兼容之前的产品。单片机集成在一个个模块式的设备中,插入机架后与机架中的处理器通讯,而每个模块采用采用线与的方式连接。ATmega8串口问题可能ATmega8的输出不是所谓的准双向口,而是普通CMOS输出...ATMega8的UART输出是推拉方式的口,和51不同的.......还是用隔
- gw1300 嵌入式系统
- 电子产品开发中常遇电磁兼容EMC问题及解决办法
- 一般电子产品都最容易出的问题有:RE--辐射,CE--传导,ESD--静电。通讯类电子产品不光包括以上三项:RE,CE,ESD,还有Surge--浪涌(雷击,打雷)医疗器械最容易出现的问题是:ESD--静电,EFT--瞬态脉冲抗干扰,CS--传导抗干扰,RS--辐射抗干扰。针对于北方干燥地区,产品的ESD--静电要求要很高。针对于像四川和一些西南多雷地区,EFT防雷要求要很高.如何提高电子产品的抗干扰能力和电磁兼容性:1、下面的一些系统要特别注意抗电磁干扰:(1
- qwqwqw2088 模拟与混合信号
设计资源 培训 开发板 精华推荐
- 使用 ON Semiconductor 的 FAN2503S 的参考设计
- ADA4841-1YRJZ 低功耗、低噪声运算放大器的典型应用电路,用于两极 500kHz 重构滤波器原理图
- FRDM33772BTPLEVB: MC33772评估板,具有隔离的菊花链通信
- 用于便携式的 1.5V DC 到 DC 单路输出电源
- NCP571SN10T1GEVB:LDO 稳压器评估板
- LTC4222 演示板,具有 I2C 兼容监控功能的双路热插拔控制器
- AP5725 升压型白光 LED 驱动器的典型应用
- LT4275CIMS LTPoE++ 38.7W 至 90W 受电设备的典型应用电路
- NCP301LSN27T1 2.7V 窗口电压检测器的典型应用
- 使用 Aimtec 的 AM3G-1203SH30Z 的参考设计