基于MSP430F5529单片机实现HC-SR04超声波测距 CCS IAR

2023-10-13 04:50

本文主要是介绍基于MSP430F5529单片机实现HC-SR04超声波测距 CCS IAR,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

基于MSP430F5529单片机实现HC-SR04超声波测距 CCS & IAR

  • 项目介绍
  • 项目准备
  • 实现原理
  • 软件设计
    • UCS设置
    • USCI_UART设置
    • TIMER_A设置
    • 主函数
  • 测试结果
  • 总结
  • 附录
    • 温度补偿

如需《ccs软件使用方法》 请联系群主或管理员,群号:176242843 。

2019.07.21更新:
可在qq群下载基于MSP430G2553单片机的HC-SR04超声波测距程序,测距原理与本文一致,开发环境为CCS,可快速移植到IAR。

2019.06.19更新:
可在qq群下载基于CCS & IAR开发环境编写的程序。

项目介绍

本设计基于TI公司的MSP430F5529单片机与超声波测距模块HC-SR04实现距离测量,使用ccs软件进行编程,利用单片机定时器的捕获模块捕获超声波高电平持续的时间,再根据公式计算出距离值。

项目准备

1. 开发环境(PC、CCS软件)
2. MSP-EXP430F5529LP .
3. HC-sr04
4. 直尺或其他量度工具

实现原理

超声波时序图
如图,只需要提供一个 10uS 以上脉冲触发信号,该模块内部将发出 8 个 40kHz 周期电平并检测回波。一旦检测到有回波信号则输出回响信号。回响信号的脉冲宽度与所测的距离成正比。 由此通过发射信号到收到的回响信号时间间隔可以计算得到距离。

本项目中通过单片机 IO 口P1.3输出10us的高电平给超声波模块 Trig触发测距,模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回; 有信号返回时 通过 IO 口P1.2 TA0.1捕获 Echo输出一个高电平, 高电平持续的时间就是超声波从发射到返回的时间。通过单片机定时器的捕获模块捕获超声波高电平持续的时间,再根据公式计算出距离值。
距离公式:

距离 = ( 高电平时间 x 声速 (340M/s)) / 2

软件设计

UCS设置

单片机时钟模块默认使用的是内部DCOCLKDIV 1.048576MHZ,本项目中使用XT2外接的4MHz高频晶振,将系统配置为;
MCLK = SMCLK = XT2 = 4MHz

void UCS_Init(void)
{
//    P1DIR |= BIT0;                            // ACLK set out to pins
//    P1SEL |= BIT0;P2DIR |= BIT2;                            // SMCLK set out to pinsP2SEL |= BIT2;
//    P7DIR |= BIT7;                            // MCLK set out to pins
//    P7SEL |= BIT7;P5SEL |= BIT2+BIT3;                       // Port select XT2UCSCTL6 &= ~XT2OFF;                       // Enable XT2UCSCTL3 |= SELREF_2;                      // FLLref = REFO// Since LFXT1 is not used,// sourcing FLL with LFXT1 can cause// XT1OFFG flag to setUCSCTL4 |= SELA_2;                        // ACLK=REFO,SMCLK=DCO,MCLK=DCO// Loop until XT1,XT2 & DCO stabilizes - in this case loop until XT2 settlesdo{UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG);// Clear XT2,XT1,DCO fault flagsSFRIFG1 &= ~OFIFG;                      // Clear fault flags}while (SFRIFG1&OFIFG);                   // Test oscillator fault flagUCSCTL6 &= ~XT2DRIVE0;                    // Decrease XT2 Drive according to// expected frequencyUCSCTL4 |= SELS_5 + SELM_5;               // SMCLK=MCLK=XT2
}

USCI_UART设置

对于给定的BRCLK时钟源,使用的波特率决定了所需的分频因子N:
N = f BRCLK / Baudrate
因子N通常是非整数值,因此,使用至少一个除法器和一个调制器级来尽可能地满足该因子。 如果N等于或大于16,则可以通过设置UCOS16来选择过采样波特率生成模式。

低频模式下,除数的整数部分由预分频器实现:
UCBRx = INT(N)
并且分数部分由调制器实现,具有以下标称公式:
UCBRSx =round [(N - INT(N))×8]
将UCBRSx设置递增或递减一个计数可以为任何给定位提供较低的最大位错误。 要确定是否是这种情况,必须为每个UCBRSx设置的每个位执行详细的错误计算。

过采样模式下,预分频器设置为:
UCBRx = INT(N / 16)
并且第一级调制器设置为:
UCBRFx = round([(N / 16) - INT(N / 16)]×16)
当需要更高的精度时,UCBRSx调制器也可以使用0到7的值来实现。要找到给出任何给定位的最低最大误码率的设置,必须对UCBRSx的所有设置执行详细的误差计算。 初始UCBRFx设置为0到7,UCBRFx设置递增并递减1。

在本项目中将通过串口打印距离值到PC端,将串口配置为 115200 8N1
首先配置串口输入时钟,工作模式等,然后配置串口的波特率:
UCBR0 = 4000000 / 115200 = 34.722222222222222222222222222222 则:UCBR0 = 34
UCBRSx =(34.72 - 34)× 8 = 5.76 四舍五入后 UCBRS = 6

void Uart_Init(void)                           // 115200 8N1
{P4SEL |= BIT4+BIT5;                        // P4.4,5 = USA1 TXD/RXDUCA1CTL1 |= UCSWRST;                       // **Put state machine in reset**UCA1CTL1 |= UCSSEL__SMCLK ;                // SMCLKUCA1BR0 = 34;                              // 4MHz 115200 (see User's Guide)// UCA1BR0 = 输入的时钟源/串口通信速率 (取整)UCA1BR1 = 0;                               // 4MHz 115200UCA1MCTL = UCBRS_6;                        // 输入的时钟源/串口通信速率的余数*8UCA1CTL1 &= ~UCSWRST;                      // **Initialize USCI state machine**
//    __bis_SR_register(GIE);       // Enter LPM0, interrupts enabled
}

TIMER_A设置

本项目中需要用到定时器的捕获模式,通过TAxCTL设置输入时钟、工作模式、中断允许等(TA0CTL)。
图1 TAxCTL 寄存器
本项目通过P1.2即TA0.1捕获超声波模块Echo引脚输出的高电平时长,配置TAxCCTLn设置工作模式、输入设置、中断允许等(TA0CCTL1)。
TAxCCTLn寄存器
配置完定时器的寄存器以后,在中断程序中计算距离值。捕获原理很简单,通过捕获电平的变化,进而得到高电平持续持续时间,首先使用捕获模式的上升沿捕获,当捕获事件发生时会触发中断,在中断中记录TA0CCR1的值并将捕获模式设置为下降沿触发,然后计算距离值,也可在中断外部计算,中断中获取定时器值。


#define Trig1(a)  if(a==1) P1OUT |= BIT3; else P1OUT &= ~BIT3unsigned int cap_new = 0;           // 首次捕捉的ta0r值
unsigned int cap_old = 0;           // 二次捕捉的ta0r值
//char test_num = 10;                 // 测量次数
char cap_N = 0;                     // 溢出次数
char state = 0x00;                  // zhuangtai
long cap_data = 0;                  // 距离值
//unsigned int dat[test_num];         //通过数组存10次测量值void Hc_sr_Init(void)			// 超声波模块初始化
{/**  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输出*/P1OUT &= ~( BIT2 + BIT3 );P1DIR |=  BIT3;P1SEL |=  BIT2;/** note:由于选用的是P1.2 根据端口定义可知,使用的是TA0CCR1,捕获输入引脚通过TA0CCTL1寄存器控制,*-捕获值存储在TA0CCR1中。* TASSEL:SNCLK; 分频:4MHz/8 = 500k;计数模式:0  ==> 0xFFFF;* TA0CCTL1:上升沿捕获 ;同步捕捉;捕获模式;CCI1A输入;*/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);__delay_cycles(40);Trig1(0);
}#pragma vector=TIMER0_A1_VECTOR
__interrupt void TIMER0_A1_ISR(void)
{switch(__even_in_range(TA0IV,14)){case  0:break;                                 // No interruptcase  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;UARTprintf("\n\ncap_data: %u mm",cap_data);TA0CCTL1 &= ~CM_2;TA0CCTL1 |=  CM_1;}else UARTprintf("\nstate: %x",state);     // 判断CM位捕捉模式
//          UARTprintf("\n yes! ccr1 \nTA0 CCR1: %u  TA0R: %u",TA0CCR1,TA0R);break;                          // CCR1 not usedcase  4: break;                          // CCR2 not usedcase  6: break;                          // reservedcase  8: break;                          // reservedcase 10: break;                          // reservedcase 12: break;                          // reservedcase 14:TA0CTL &= ~TAIFG;if(cap_old   < cap_new ){cap_N += 1;}break;                          // overflowdefault: break;}
}

主函数

主函数中对各个模块初始化,死循环执行超声波模块触发函数。


int main(void) {WDT_A_hold(WDT_A_BASE);UCS_Init();Uart_Init();Hc_sr_Init();__bis_SR_register(GIE);UARTprintf("\nInitialization is complete!");while(1){Hc_sr_Open();__delay_cycles(1000000);}
}

测试结果

由于室内空间有限,只测试了部分距离。为了方便观察数据,对数据进行了简单的换算。测试中发现,在距离较近时误差较大,引起误差的原因很多,例如程序算法、模块自身、温度等,本项目仅实现简单的超声波测距功能,如需高精度的测量可为其添加温度补偿功能,进一步提高测量精度。

测试距离(CM)实际距离(CM)
44.3
88.2
1010.1
2020.1
3030.1
190191

总结

本项目实现了一个简单的超声波测距功能,其中最复杂的部分属于定时器模块的配置。在设计中通过串口输出温度值,可能对测试值产生误差。在项目期间遇到了只能测量10厘米以上的距离,经过测试后发现是算法原因,原因是声速值取错了,导致不能测量十厘米以下的距离。

附录

温度补偿

公式:
超声波温度补偿公式

温度(℃)-30-20-100102030100
声速(M/S)313319325332338344349386

第一次写,经验不足,如有不足或错误,敬请指教。
如需程序源码请私信或加QQ群:176242843
原创作品,转载请注明。

这篇关于基于MSP430F5529单片机实现HC-SR04超声波测距 CCS IAR的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/200872

相关文章

Java实现时间与字符串互相转换详解

《Java实现时间与字符串互相转换详解》这篇文章主要为大家详细介绍了Java中实现时间与字符串互相转换的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、日期格式化为字符串(一)使用预定义格式(二)自定义格式二、字符串解析为日期(一)解析ISO格式字符串(二)解析自定义

opencv图像处理之指纹验证的实现

《opencv图像处理之指纹验证的实现》本文主要介绍了opencv图像处理之指纹验证的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录一、简介二、具体案例实现1. 图像显示函数2. 指纹验证函数3. 主函数4、运行结果三、总结一、

Springboot处理跨域的实现方式(附Demo)

《Springboot处理跨域的实现方式(附Demo)》:本文主要介绍Springboot处理跨域的实现方式(附Demo),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录Springboot处理跨域的方式1. 基本知识2. @CrossOrigin3. 全局跨域设置4.

Spring Boot 3.4.3 基于 Spring WebFlux 实现 SSE 功能(代码示例)

《SpringBoot3.4.3基于SpringWebFlux实现SSE功能(代码示例)》SpringBoot3.4.3结合SpringWebFlux实现SSE功能,为实时数据推送提供... 目录1. SSE 简介1.1 什么是 SSE?1.2 SSE 的优点1.3 适用场景2. Spring WebFlu

基于SpringBoot实现文件秒传功能

《基于SpringBoot实现文件秒传功能》在开发Web应用时,文件上传是一个常见需求,然而,当用户需要上传大文件或相同文件多次时,会造成带宽浪费和服务器存储冗余,此时可以使用文件秒传技术通过识别重复... 目录前言文件秒传原理代码实现1. 创建项目基础结构2. 创建上传存储代码3. 创建Result类4.

SpringBoot日志配置SLF4J和Logback的方法实现

《SpringBoot日志配置SLF4J和Logback的方法实现》日志记录是不可或缺的一部分,本文主要介绍了SpringBoot日志配置SLF4J和Logback的方法实现,文中通过示例代码介绍的非... 目录一、前言二、案例一:初识日志三、案例二:使用Lombok输出日志四、案例三:配置Logback一

Python如何使用__slots__实现节省内存和性能优化

《Python如何使用__slots__实现节省内存和性能优化》你有想过,一个小小的__slots__能让你的Python类内存消耗直接减半吗,没错,今天咱们要聊的就是这个让人眼前一亮的技巧,感兴趣的... 目录背景:内存吃得满满的类__slots__:你的内存管理小助手举个大概的例子:看看效果如何?1.

Python+PyQt5实现多屏幕协同播放功能

《Python+PyQt5实现多屏幕协同播放功能》在现代会议展示、数字广告、展览展示等场景中,多屏幕协同播放已成为刚需,下面我们就来看看如何利用Python和PyQt5开发一套功能强大的跨屏播控系统吧... 目录一、项目概述:突破传统播放限制二、核心技术解析2.1 多屏管理机制2.2 播放引擎设计2.3 专

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

idea中创建新类时自动添加注释的实现

《idea中创建新类时自动添加注释的实现》在每次使用idea创建一个新类时,过了一段时间发现看不懂这个类是用来干嘛的,为了解决这个问题,我们可以设置在创建一个新类时自动添加注释,帮助我们理解这个类的用... 目录前言:详细操作:步骤一:点击上方的 文件(File),点击&nbmyHIgsp;设置(Setti