目录
前言
一、超声波介绍
二、部分代码
三、总结
哎,又双叒叕,电赛延期了,看起来像是遥遥无期,但是肯定要考虑大局,大家就继续抓紧时间学习知识,巩固自己的知识,更进一步。好了,今天主要是继承上一篇博文(OLED显示)写的,主要是写超声波测距的(US-015)
利用TI公司的MSP430F5529单片机+超声波模块+OLED 实现
这里主要是利用单片机定时器的捕获功能来捕获超声波高电平持续时间,再计算得到距离,最后再在OLED 屏幕上显示出来,上图:
这里是把数字用了32号的,比较清晰,大家也可以自己更改
具体怎么接OLED 屏幕上一讲里面代码也有详细介绍,这里的超声波模块的Trig我接的是1.3,Echo接的是1.2
P1.2 为echo 设置为捕获模式
介绍:P1.2 具有端口中断的通用数字I / O ,TA0 CCR1捕获:CCI1A输入,比较:Out1输出 BSL接收输入
P1.3 为Trig 设置为 数字i/o模式
介绍:P1.3 具有端口中断的通用数字I / O , TA0 CCR2捕获:CCI2A输入,比较:Out2输出
超声波模块初始化
void US_015_Init(void)
{
P1OUT &= ~( BIT2 + BIT3 );
P1DIR |= BIT3;
P1SEL |= BIT2;
TA0CTL = TASSEL__SMCLK + ID__8 + MC_2 + TACLR + TAIE;
TA0CCTL1 = CM_1 + SCS +CAP + CCIE + CCIS_0;
}
void Hc_sr_Open(void) //生成一个持续10us的高电平
{
Trig1(1);//这里就是把P1.2置1,即P1OUT |= BIT2
__delay_cycles(250);//这里我把系统时钟升为25MHZ,因此250/25000000=10us
Trig1(0);置0
}
我们选用的是P1.2, 根据端口定义,使用的是TA0CCR1,捕获输入引脚通过TA0CCTL1寄存器控制,捕获值存储在TA0CCR1中。
TASSEL(时钟源选择):SMCLK; ID分频(下面介绍):(这里分频系数会影响后面计算)4MHz/8 = 500k;计数模式:0 ==> 0xFFFF; 定时器清零位 ;中断使能。
TA0CCTL1:上升沿捕获 ;同步捕捉;捕获模式;中断使能;CCI1A输入。
(这里查了一下SCS和CAP都有两种模式,但是这里直接就是把寄存器代码搞上去,没有分出0和1两种模式,这里搞不太懂,哪位大佬解惑解惑?)
CM的四种模式:不捕获、上升沿捕获、下降沿捕获、上升下降都捕获
原理:这里其实就是复用P1.2口为捕获,通过P1.3发出一个10us的高电平给超声波TRIG口触发进行测距,模块内部就返回一个信号,P1.2就捕获一个返回的高电平持续时间,再计算得出距离
公式:s=高电平持续时间*声速340/2(因为上面分频采用了8分频,因此我下面计算就不用除以2)
定时中断函数:
#pragma vector=TIMER0_A1_VECTOR
__interrupt void TIMER0_A1_ISR(void)
{
switch(__even_in_range(TA0IV,14))//采用这个range函数就是为了使switch函数效率高
{
case 0:break; // No interrupt
case 2:
state = TA0CCTL1 >> 14;
TA0CCTL1 &= ~CCIFG;//标志位清零
if( TA0CCTL1 & CM_1){//开始捕获高电平时间
cap_new = TA0CCR1;
TA0CCTL1 &= ~CM_1;
TA0CCTL1 |= CM_2;
}else if ( TA0CCTL1 & CM_2){
cap_old = TA0CCR1;
cap_data = ( cap_old - cap_new ) * 0.34/10/6.25;//这里外面解释!
Gui_DrawFont_Num32(10,50,BLUE,GRAY0,cap_data/100);//显示数字
Gui_DrawFont_Num32(37,50,BLUE,GRAY0,cap_data/10%10);
Gui_DrawFont_Num32(64,50,BLUE,GRAY0,cap_data%10);
TA0CCTL1 &= ~CM_2;
TA0CCTL1 |= CM_1;
}else
break; // CCR1 not used
case 4: break; // CCR2 not used
case 6: break; // reserved
case 8: break; // reserved
case 10: break; // reserved
case 12: break; // reserved
case 14:
TA0CTL &= ~TAIFG;
if(cap_old < cap_new ){
cap_N += 1;
}
break; // overflow
default: break;
}
}
这里其实都挺好理解的,就是大家可能对那个cap_data计算不太理解,首先为什么不除以2,是因为上面分频系数为8,(如果改为4,那么就应该除以2了),具体我也是测试出来的,至于为啥我觉得可能是分频系数为4时分频后频率为1MHZ,这样分频速率是最为正确的,但是8分频后为500KHZ就影响了原有的,相当于除以2了,哪位大佬可以帮忙解答哈哈,MSP430F5529我研究不是很长哈哈。然后后面除以10是因为计算的结果是MM为单位,我这里是以CM为单位,因此除以10;除以6.25是因为我升的时钟频率为25MHZ,跟原先的定时器4MHZ不对应,因此要换算即25/4=6.25,因此除以6.25。
最后面主函数:
int main(void) {
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
upVcc();//升压
timerup();//时钟频率升为25MHZ
Lcd_Init();
LCD_LED_SET;//通过IO控制背光亮
Lcd_Clear(WHITE); //清屏
Hc_sr_Init();
__bis_SR_register(GIE);//开启中断
Gui_DrawFont_GBK16(10,0,BLUE,GRAY0,"电子2班");
Gui_DrawFont_GBK16(10,20,BLUE,GRAY0,"Dis:");
Gui_DrawFont_GBK24(100,60,BLUE,GRAY0,"CM");
while(1){
Hc_sr_Open();
__delay_cycles(1000000);
}
}
对了,漏了一些声明
#define Trig1(a) if(a==1) P1OUT |= BIT3; else P1OUT &= ~BIT3
unsigned int cap_new = 0; // 首次捕捉的ta0r值
unsigned int cap_old = 0; // 第二次捕捉的ta0r值
char cap_N = 0; // 溢出次数
char state = 0x00; // 状态
u16 cap_data ; // 距离值,u16
到这里你可能对超声波测距有一个概念了,但是不够,一定要亲自上手实验,多琢磨,不要贪图省事,这样对你没有好处。
其实这里无非就是对定时器的应用,然后一些测量结果可能会出现误差,这是无法避免的,但是大体上影响不大,如果你不追求高精度测距和长距离测距的话,那么超声波测距是很好的选择!
这里我也是才学习这款单片机不久,有哪里写的不好的请见谅,有错误可以随时指正,欢迎大家踊跃评论,一起探讨交流,一起进步,谢谢!
题外话
挺喜欢彭于晏说的一句话:“我就是没有才华,所以才用命去拼!”
学习32之路固然辛苦,但要是坚持下来了,那不是很酷?哈哈哈