ARM程序设计题目与复习文档格式.docx
《ARM程序设计题目与复习文档格式.docx》由会员分享,可在线阅读,更多相关《ARM程序设计题目与复习文档格式.docx(20页珍藏版)》请在冰豆网上搜索。
编写程序外部通道输入一个电压,并用ADC的DMA模式采样100个数据,然后用UART将ADC采样的100个电压数据传输到电脑上。
voidAdc_Init(void)
{
//先初始化IO口
APB2ENR|=1<
//使能PORTA口时钟
GPIOA->
CRL&
=0XFFFFFF0F;
//PA1anolog输入
//通道10/11设置
9;
//ADC1时钟使能
APB2RSTR|=1<
//ADC1复位
APB2RSTR&
=~(1<
9);
//复位结束
CFGR&
=~(3<
14);
//分频因子清零
//SYSCLK/DIV2=12MADC时钟设置为12M,ADC最大时钟不能超过14M!
//否则将导致ADC准确度下降!
CFGR|=2<
14;
ADC1->
CR1&
=0XF0FFFF;
//工作模式清零
CR1|=0<
//独立工作模式
8);
//非扫描模式
CR2&
1);
//单次转换模式
=~(7<
17);
CR2|=7<
17;
//软件控制转换
CR2|=1<
20;
//使用用外部触发(SWSTART)!
!
必须使用一个事件来触发
8;
//使用DMA
11);
//右对齐
SQR1&
=~(0XF<
20);
SQR1|=0<
//1个转换在规则序列中也就是只转换规则序列1
//设置通道1的采样时间
SMPR2&
3);
//通道1采样时间清空
ADC1->
SMPR2|=7<
3;
//通道1239.5周期,提高采样时间可以提高精确度
0;
//开启AD转换器
//使能复位校准
while(ADC1->
1<
//等待校准结束
//该位由软件设置并由硬件清除。
在校准寄存器被初始化后该位将被清除。
//开启AD校准
2);
//等待校准结束
//该位由软件设置以开始校准,并在校准结束时由硬件清除
//获取通道ch的转换值,取times次,然后平均
//ch:
通道编号
//times:
获取次数
//返回值:
通道ch的times次转换结果平均值
u16Get_Adc_Average(u8ch,u8times)
u32temp_val=0;
u8t;
for(t=0;
t<
times;
t++)
{
temp_val+=Get_Adc(ch);
delay_ms(5);
}
returntemp_val/times;
//pclk2:
PCLK2时钟频率(Mhz)
//bound:
波特率
voiduart_init(u32pclk2,u32bound)
{
floattemp;
u16mantissa;
u16fraction;
temp=(float)(pclk2*1000000)/(bound*16);
//得到USARTDIV
mantissa=temp;
//得到整数部分
fraction=(temp-mantissa)*16;
//得到小数部分
mantissa<
=4;
mantissa+=fraction;
//使能串口时钟
CRH&
=0XFFFFF00F;
//IO状态设置
CRH|=0X000008B0;
//复位串口1
//停止复位
//波特率设置
USART1->
BRR=mantissa;
//波特率设置
USART1->
CR1|=0X200C;
//1位停止,无校验位.
#ifEN_USART1_RX//如果使能了接收
//使能接收中断
CR1|=1<
//PE中断使能
5;
//接收缓冲区非空中断使能
MY_NVIC_Init(3,3,USART1_IRQChannel,2);
//组2,最低优先级
#endif
#include"
sys.h"
usart.h"
delay.h"
adc.h"
u16adcx,i;
Stm32_Clock_Init(9);
//系统时钟设置
uart_init(72,9600);
//串口初始化为9600
delay_init(72);
//延时初始化
Adc_Init();
//ADC初始化
while
(1)
{
for(i=0;
i<
100;
i++)//采集100个数据,循环100次
{adcx=Get_Adc_Average(ADC_CH1,10);
//转换一次
DR=adcx;
//把数据送到发送缓存区
while((USART1->
SR&
(1<
6))==0);
//等待发送完成
6);
//清除标志位
}
GPIO口实现LED1灯以0.1s闪烁2s。
//初始化PB5和PE5为输出口.并使能这两个口的时钟
//LEDIO初始化
voidLED_Init(void)
//使能PORTB时钟
6;
//使能PORTE时钟
GPIOB->
=0XFF0FFFFF;
CRL|=0X00300000;
//PB.5推挽输出
ODR|=1<
//PB.5输出高
GPIOE->
//PE.5推挽输出
//PE.5输出高
//通用定时器3中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:
自动重装值。
//psc:
时钟预分频数
//这里使用的是定时器3!
voidTIM3_Int_Init(u16arr,u16psc)
APB1ENR|=1<
1;
//TIM3时钟使能
TIM3->
ARR=arr;
//设定计数器自动重装值//刚好1ms
TIM3->
PSC=psc;
//预分频器7200,得到10Khz的计数时钟
DIER|=1<
//允许更新中断
CR1|=0x01;
//使能定时器3
MY_NVIC_Init(1,3,TIM3_IRQChannel,2);
//抢占1,子优先级3,组2
timer.h"
led.h"
{
Stm32_Clock_Init(9);
LED_Init();
TIM3_Int_Init(499,7199);
//10Khz的计数频率,计数500次为0.05s
while
(1)
u16c=40;
//定义40次,正好是2s
voidTIM3_IRQHandler(void)
{
if(TIM3->
0X0001)//溢出中断
{if(c)
{LED1=!
LED1;
c--;
}
}
0);
//清除中断标志位
PWM
//TIM3PWM部分初始化
//PWM输出初始化
自动重装值
voidTIM3_PWM_Init(u16arr,u16psc)
{
//此部分需手动修改IO口设置
//TIM3时钟使能
//使能PORTB时钟
//PB5输出
CRL|=0X00B00000;
//复用功能输出
//开启辅助时钟
AFIO->
MAPR&
=0XFFFFF3FF;
//清除MAPR的[11:
10]
MAPR|=1<
11;
//部分重映像,TIM3_CH2->
PB5
//设定计数器自动重装值
//预分频器不分频
CCMR1|=7<
12;
//CH2PWM2模式
CCMR1|=1<
//CH2预装载使能
CCER|=1<
4;
//OC2输出使能
CR1=0x0080;
//ARPE使能
//使能定时器3
TIM3_PWM_Init(899,0);
//不分频。
PWM频率=72000/(899+1)=80Khz
CCR2=200;
//占空比赋值
CAN
/CAN初始化
//tsjw:
重新同步跳跃时间单元.范围:
1~3;
//tbs2:
时间段2的时间单元.范围:
1~8;
//tbs1:
时间段1的时间单元.范围:
1~16;
//brp:
波特率分频器.范围:
1~1024;
(实际要加1,也就是1~1024)tq=(brp)*tpclk1
//注意以上参数任何一个都不能设为0,否则会乱.
//波特率=Fpclk1/((tbs1+tbs2+1)*brp);
//mode:
0,普通模式;
1,回环模式;
//Fpclk1的时钟在初始化的时候设置为36M,如果设置CAN_Normal_Init(1,8,7,5,1);
//则波特率为:
36M/((8+7+1)*5)=450Kbps
0,初始化OK;
//其他,初始化失败;
u8CAN_Mode_Init(u8tsjw,u8tbs2,u8tbs1,u16brp,u8mode)
u16i=0;
if(tsjw==0||tbs2==0||tbs1==0||brp==0)return1;
tsjw-=1;
//先减去1.再用于设置
tbs2-=1;
tbs1-=1;
brp-=1;
//使能PORTA时钟
=0XFFF00FFF;
CRH|=0X000B8000;
//PA11RX,PA12TX推挽输出
ODR|=3<
25;
//使能CAN时钟CAN使用的是APB1的时钟(max:
36M)
CAN->
MCR=0x0000;
//退出睡眠模式(同时设置所有位为0)
MCR|=1<
//请求CAN进入初始化模式
while((CAN->
MSR&
0)==0)
i++;
if(i>
100)return2;
//进入初始化模式失败
MCR|=0<
7;
//非时间触发通信模式
//软件自动离线管理
//睡眠模式通过软件唤醒(清除CAN->
MCR的SLEEP位)
//禁止报文自动传送
//报文不锁定,新的覆盖旧的
//优先级由报文标识符决定
BTR=0x00000000;
//清除原来的设置.
BTR|=mode<
30;
//模式设置0,普通模式;
BTR|=tsjw<
24;
//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位
BTR|=tbs2<
//Tbs2=tbs2+1个时间单位
BTR|=tbs1<
//Tbs1=tbs1+1个时间单位
BTR|=brp<
//分频系数(Fdiv)为brp+1
//波特率:
Fpclk1/((Tbs1+Tbs2+1)*Fdiv)
MCR&
//请求CAN退出初始化模式
0)==1)
0XFFF0)return3;
//退出初始化模式失败
//过滤器初始化
FMR|=1<
//过滤器组工作在初始化模式
FA1R&
//过滤器0不激活
FS1R|=1<
//过滤器位宽为32位.
FM1R|=0<
//过滤器0工作在标识符屏蔽位模式
FFA1R|=0<
//过滤器0关联到FIFO0
sFilterRegister[0].FR1=0X00000000;
//32位ID
sFilterRegister[0].FR2=0X00000000;
//32位MASK
FA1R|=1<
//激活过滤器0
FMR&
=0<
//过滤器组进入正常模式
#ifCAN_RX0_INT_ENABLE
//使用中断接收
IER|=1<
//FIFO0消息挂号中断允许.
MY_NVIC_Init(1,0,USB_LP_CAN_RX0_IRQChannel,2);
//组2
return0;
/id:
标准ID(11位)/扩展ID(11位+18位)
//ide:
0,标准帧;
1,扩展帧
//rtr:
0,数据帧;
1,远程帧
//len:
要发送的数据长度(固定为8个字节,在时间触发模式下,有效数据为6个字节)
//*dat:
数据指针.
0~3,邮箱编号.0XFF,无有效邮箱.
u8Can_Tx_Msg(u32id,u8ide,u8rtr,u8len,u8*dat)
u8mbox;
if(CAN->
TSR&
26))mbox=0;
//邮箱0为空
elseif(CAN->
27))mbox=1;
//邮箱1为空
28))mbox=2;
//邮箱2为空
elsereturn0XFF;
//无空邮箱,无法发送
sTxMailBox[mbox].TIR=0;
//清除之前的设置
if(ide==0)//标准帧
id&
=0x7ff;
//取低11位stdid
id<
=21;
}else//扩展帧
=0X1FFFFFFF;
//取低32位extid
=3;
sTxMailBox[mbox].TIR|=id;
sTxMailBox[mbox].TIR|=ide<
sTxMailBox[mbox].TIR|=rtr<
len&
=0X0F;
//得到低四位
sTxMailBox[mbox].TDTR&
=~(0X0000000F);
sTxMailBox[mbox].TDTR|=len;
//设置DLC.
//待发送数据存入邮箱.
sTxMailBox[mbox].TDHR=(((u32)dat[7]<
24)|
((u32)dat[6]<
16)|
((u32)dat[5]<
8)|
((u32)dat[4]));
sTxMailBox[mbox].TDLR=(((u32)dat[3]<
((u32)dat[2]<
((u32)dat[1]<
((u32)dat[0]));
sTxMailBox[mbox].TIR|=1<
//请求发送邮箱数据
returnmbox;
//接收数据
//fifox:
邮箱号
//id:
接收到的数据长度(固定为8个字节,在时间触发模式下,有效数据为6个字节)
//dat:
数据缓存区
voidCan_Rx_Msg(u8fifox,u32*id,u8*ide,u8*rtr,u8*len,u8*dat)
*ide=CAN->
sFIFOMailBox[fifox].RIR&
0x04;
//得到标识符选择位的值
if(*ide==0)//标准标识符
*id=CAN->
sFIFOMailBox[fifox].RIR>
21;
}else//扩展标识符
*rtr=CAN->
0x02;
//得到远程发送请求值.
*len=CAN->
sFIFOMailBox[fifox].RDTR&
0x0F;
//得到DLC
//*fmi=(CAN->
sFIFOMailBox[FIFONumber].RDTR>
8)&
0xFF;
//得到FMI
//接收数据
dat[0]=CAN->
sFIFOMailBox[fifox].RDLR&
0XFF;
dat[1]=(CAN->
sFIFOMailBox[fifox].RDLR>
dat[2]=(CAN->
16)&
dat[3]=(CAN->
24)&
dat[4]=CAN->
sFIFOMailBox[fifox].RDHR&
dat[5]=(CAN->
sFIFOMailBox[fifox].RDHR>
dat[6]=(CAN->
dat[7]=(CAN->
if(fifox==0)CAN->
RF0R|=0X20;
//释放FIFO0邮箱
elseif(fifox==1)CAN->
RF1R|=0X20;
//释放FIFO1邮箱
//按键初始化函数
voidKEY_Init(void)
//使能PORTA时钟
//使能PORTE时钟
=0XFFFFFFF0;
//PA0设置成输入,默认下拉
CRL|=0X00000008;
=0XFFF000FF;
//PE2~4设置成输入
CRL|=0X00088800;
ODR|=7<
//PE2~4上拉
//按键处理函数
//返回按键值
0,不支持连续按;
1,支持连续按;
//0,没有任何按键按下
//1,KEY0按下
//2,KEY1按下
//3,KEY2按下
//4,KEY3按下WK_UP
//注意此函数有响应优先级,KEY0>
KEY1>
KEY2>
KEY3!
u8KEY_Scan(u8mode)
staticu8key_up=1;
//按键按松开标志
if(mode)key_up=1;
//支持连按
if(key_up&
&