-
CC2530 + HC-SR04
-
结合超声波模块及Timer1定时器实现超声波测距(倒车雷达)
一、(完整代码)
- buzzer.h
#include <ioCC2530.h>
#include <string.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define buzzer P2_0
uchar time, count,t3count;//用于定时器计数
//单片机晶振采用32MHz Tcy = 256 * (1/16000000)=16us;
// 频率周期数据表
__code const uchar FREQL[] = {1, //0的时候没有音符
239, 213, 189, 179, 159, 142, 127, //低音1234567 3.817ms 3.401ms 3.030ms 2.858ms 2.552ms 2.273ms 2.024ms
119, 106, 95, 90, 80, 71, 63, 60,//1,2,3,4,5,6,7,i 1.908ms 1.700ms 1.514ms 1.432ms 1.276ms 1.136ms 1.012ms 0.955ms
53, 48, 45, 40, 36, 32, //高音 234567 0.852ms 0.759ms 0.717ms 0.638ms 0.568ms 0.506ms
30, 27, 24, 22, 20, 18, 16}; //超高音 1234567 0.478ms 0.426ms 0.379ms 0.358ms 0.319ms 0.284ms 0.253ms
/******蜂鸣器输出初始化******/
void Buzzer_Init(void)
{
P2DIR |= 0x01; //P2_0定义为输出
buzzer = 1;
}
/**************每次发出的声音*****************/
__code const uchar voice[]={
5,3,1,0,0,0
};
/******中断初始化****/
void InitT3()
{
T3CTL |= 0x08 ; //开溢出中断
T3IE = 1; //开总中断和T3中断
T3CTL&=~0xE0; //1分频,Tcy = 256 * (1/16000000)=16us; 其中256是timer3 装满一次是256步
T3CTL &= ~0X03; //自动重装 00->0xff
EA = 1;
}
/********延时********/
void delay1(uint n)
{
uint tt;
for(tt = 0;tt<n;tt++);
for(tt = 0;tt<n;tt++);
for(tt = 0;tt<n;tt++);
for(tt = 0;tt<n;tt++);
for(tt = 0;tt<n;tt++);
}
/*********延时程序,控制发音的时间长度(1/4拍)*************/
void delay(uchar t)
{
uchar t1;
ulong t2;
for(t1 = 0; t1 < t; t1++) //双重循环, 共延时t个半拍
for(t2 = 0; t2 < 100; t2++); //延时期间
T3CTL &=~0x10; //关闭timer3, 停止发音
}
/****************演奏一个音符*****************/
void singachar()
{
T3CTL &=~0x10; //关闭timer3
count = t3count; //控制音调
T3CTL |=0X10; //启动, 由timer3输出方波去发音
delay(time);
delay(2);
//控制时间长度即 节拍
}
/**************发音***********************************/
void song(uchar const __code *str)
{
uchar k,i;
i = 0;
time = 1;
while(time)
{
k = str[i] + 7 * (str[i + 1]);//第i个是音符, 第i+1个是第几个八度
//从数据表中读出频率数值
t3count = FREQL[k]; //实际上, 是定时的时间长度
time = str[i + 2]; //读出时间长度数值 节拍时间
i += 3;
singachar();
}
}
/********发音模式选择***********
模式一 快速的短鸣
模式二 有停顿的短鸣
模式三 长鸣
********************************/
void play(int i)
{
//int msec = 1000;
Buzzer_Init(); //初始化IO
InitT3();
if(i==1) //模式一
{
uint i;
for (i=0; i<2; i++)
{
song(voice);//播放声音
}
}
if(i==3) //模式三
{
uint m,n;
for (m=0; m<2; m++)
for (n=0; n<2; n++)
{
// if((IRCON &0x08) =0x08 )
// {
// buzzer = ~buzzer;
// }
buzzer = 0;
delay1(10);
buzzer = 1;
delay1(10);
}
}
if(i==2) //模式二
{
uint k;//,l
for (k=0; k<2;k++)
{
song(voice);
delay(5);
}
}
}
/*
void main(void)
{
while(1)
{
play(3);
}
}
*/
/*******中断处理*********/
#pragma vector = T3_VECTOR
__interrupt void T3_ISR(void) //timer3中断处理
{
IRCON = 0x00; //清中断标志, 也可由硬件自动完成
if(--count == 0)
{
T3CTL &=~0X10; //关闭timer3
buzzer = ~buzzer; //输出方波, 发音
T3CTL |=0X10; //启动
count = t3count; //下次的中断时间, 这个时间, 控制音调高低
}
}
- Radar_ranging.c
#include<iocc2530.h>
#include<string.h>
#include "buzzer.h"
#define ECHO P0_0 //ECHO引脚接在P0_0脚
#define TRIG P0_1 //TRIG引脚接在P2_0脚
//#define Buzzer P2_0 //蜂鸣器引脚
unsigned int count_Time; //用于存放计数值
float distance; //存放距离值,float型提高测距精度
unsigned char count_TimeH; //用于存放计数值高8位
unsigned char count_TimeL; //用于存放计数值低8位
char buf[10]; //存放串口发送数据
float D;
/*延时1us函数*/
void delay_1us(int m){
while(m--){
asm("NOP");
asm("NOP");
asm("NOP");
}
}
/*延时1ms函数*/
void delayms(unsigned int ms)
{
unsigned int i, j;
for(i = ms; i > 0; i--)
for(j = 578; j > 0; j--);
}
/*时钟初始化*/
void clk_Init(){
CLKCONCMD &= ~0X40; //设置第6位OSC系统时钟源为32MHZ晶振
while(CLKCONSTA & 0x40); //等待晶振稳定
CLKCONCMD &= ~0x3f; //设置系统主时钟为32MHZ,定时器标记输出设置为32MHZ,时钟速度32MHZ
}
/*串口初始化*/
void usart_Init(){
PERCFG &= ~0x01; //USART0备用位置1
P0SEL |= 0x0c; //P0_2-P0_3为外设
P2DIR &= ~0xc0; //端口0外设优先级配置
U0CSR |= 0X80; //设置为UART模式
U0GCR |= 11; //设置波特率为115200
U0BAUD |= 216;
UTX0IF = 0;
}
/*I/O初始化*/
void io_Init(){
P0SEL &= ~0x02; //P0_1作为通用I/O
P0DIR |= 0X02; //P0_1作为输出口
P0SEL &= ~0x01; //P0_0作为通用I/O
P0DIR &= ~0X01; //P0_0作为输入口
//P2SEL |= 0x01; //
//P2DIR |= 0x01; //
//Buzzer = 1; //
//P0IF = 0; //清除端口0中断标志
//P0IE = 1; //允许P0口中断
P0IFG = 0x00; //*P0中断标志清零P35
//P0INP &= ~0X00; //*P0_0上拉或下拉
P0IEN |= 0x01; //开启P0_0外部中断
PICTL |= 0x01; //P0下降沿中断
IRCON = 0x00; //设置P0无端口未决
IEN1 |= 0x20; //*设置P0中断使能P38
EA = 1; //*开总中断
}
/*定时器1初始化*/
void timer1_Init(){
T1CTL &= ~0x03; //停止运行
T1CTL |= 0X0c; //设置为128分频
T1CNTH = 0x00;
T1CNTL = 0x00;
}
/*HC_RS04初始化*/
void hc_sr04_Init(){
TRIG = 1;
delay_1us(20);
TRIG = 0;
while(!ECHO);
T1CTL |= 0x01; //开始自由运行模式
}
/*串口发送函数*/
void send(char *s){
while(*s!='\0'){
U0DBUF= *s++;
while(UTX0IF == 0); //等待标志位置1,为1时,表示当前字节发送完了
UTX0IF = 0;
}
}
/*P0口中断*/
#pragma vector = P0INT_VECTOR
__interrupt void P0_isr(){
if(P0IFG&0x01){ //判断是否是P0_0中断
T1CTL &= ~0x03; //停止T1运行
P0IF = 0; //清除端口0中断标志
P0IFG &= ~0x01; //清除P0_0中断状态标志
count_TimeH = T1CNTH; //取出定时器 1 计数器高位
count_TimeL = T1CNTL; //取出定时器 1 计数器低位
}
}
int main(){
clk_Init();
io_Init();
usart_Init();
// P1SEL |= 0x04;
// P1DIR |= 0x04; //P1_2定义为输出
// Buzzer = 0;
Buzzer_Init();
int cnt=0;
int sum=0;
float temp=1000;
// InitT3(); //
// singachar(); //
while(1){
cnt++;
timer1_Init(); //定时器初始化
hc_sr04_Init(); //HC_SR04初始化
// delayms(10);
count_Time = count_TimeH*256+count_TimeL;//计算定时器1计数值
distance = count_Time*0.068; //计算距离
D = distance;
if(cnt<=5)
{
sum+=D;
}
if(cnt>5)
{
sum/=5;
temp=sum;
sum=0;
cnt=0;
/*将浮点数转为字符串,便于发送(这里只保留了两位小数)*/
buf[0] = (unsigned int)temp/100+48;
buf[1] = (unsigned int)distance%100/10+48;
buf[2] = (unsigned int)distance%10+48;
buf[3] = '.';
buf[4] = (unsigned int)(distance*10)%10+48;
buf[5] = (unsigned int)(distance*100)%10+48;
buf[6] = '\n';
send(buf);
memset(buf,0,10);
//清空数组
}
if(0<temp && temp<20)
{
// Buzzer=0;
// delay_1us(10);
// Buzzer=1;
buzzer = 0;
delay_1us(50);
}
if(20<=temp && temp<60)
{
// Buzzer=0;
// delay_1us(5);
// Buzzer=1;
// delay_1us(5);
buzzer = 1 ;
delay_1us(800);
buzzer = 0;
delay_1us(800);
}
else if(temp>60 && temp<100){
// Buzzer=0;
// delay_1us(10);
// Buzzer=1;
// delay_1us(10);
buzzer = 1 ;
delay_1us(1500);
buzzer = 0;
delay_1us(1500);
}
else if(temp>100){
buzzer = 1;
delay_1us(100);
}
/*
//将浮点数转为字符串,便于发送(这里只保留了两位小数)
buf[0] = (unsigned int)temp/100+48;
buf[1] = (unsigned int)distance%100/10+48;
buf[2] = (unsigned int)distance%10+48;
buf[3] = '.';
buf[4] = (unsigned int)(distance*10)%10+48;
buf[5] = (unsigned int)(distance*100)%10+48;
buf[6] = '\n';
send(buf);
memset(buf,0,10);
//清空数组
*/
}
}
- 可以根据距离 蜂鸣器变速响
- 但 是用延时写的,最好用定时器
二、(关键部分)
- 自由模式
#include <ioCC2530.h>
//#include "sound.h"
#define TRIG P0_0
#define ECHO P0_1
#define SPK P2_0
unsigned char ms_cnt = 0;
unsigned char err_flag = 0;
void rada_init(void);
int mark;
int getdistance();
void hc_sr04_init(void);
void Buzzer_Init(void);
void delay_10us(void);
void Buzzer_Init(void);
void led_init(void);
void main(void)
{
led_init();
rada_init();
hc_sr04_init();
Buzzer_Init();
while(1)
{
mark = getdistance();
if(mark <= 60){
//buzzer = 1;
LED1 = ON;
}else{
//buzzer = 0;
LED1 = OFF;
}
}
}
void rada_init(void)
{
P0SEL &= ~0x03;//普通IO置0,或者外设置1
P0DIR |= 0x01;//方向:输出置1
P0DIR &= 0x02;//输入置0
P0INP &= 0x02;//置0,上拉/下拉
P2INP |= 0x20;//置1,端口0所有引脚下拉
P2SEL &= ~0x01;
P2DIR |= 0x01;
T1CTL = 0x04;//分频,2N
T1CNTL = 0x00;
T1CNTH = 0x00;
T1CC0L = 0x00;
T1CC0H = 0x07;
IEN1 |= 0x02; //端口0中断使能
IRCON = 0x00;//中断标志寄存器 置0,无中断未决
EA = 1;//开中断
}
//中断
#pragma vector=T1_VECTOR
__interrupt void time_ISR(void)
{
if(T1STAT&0x20)//定时器1计数器溢出中断标志
{
err_flag = 1;
}
IRCON&=~0x02;
}
void hc_sr04_init()
{
TRIG=1;
delay_10us();//提供一个10us以上脉冲触发信号
TRIG=0;
while(!ECHO);
T1CTL |= 0x01; //开始自由运行模式
}
int getdistance()
{
unsigned char i;
int distance = 0;
unsigned char val;
int reg_val = 0;
for(i = 0; i < 5; i++)
{
TRIG = 1;
delay_10us();
TRIG = 0;
while(!ECHO);
T1CTL &= ~0x03;//先清零
T1CTL |= 0x01;//自由u模式启动
while(ECHO){
if(!err_flag)
{
T1CTL &= ~0x03;
T1CNTL = 0x00;
T1CNTH |= 0x00;
err_flag = 0;
return 0;//非正常结束
}
}
//测量正确
T1CTL &= ~0x03;
val = T1CNTL;
reg_val = T1CNTH;
reg_val = ((reg_val<<8) | val)>>1;
distance += reg_val/59;//
T1CNTL = 0x00;
T1CNTH = 0x00;
}
return distance;
}
void delay_10us(void)
{
int i;
for(i = 0; i < 10; i++);
}
/******蜂鸣器输出初始化******/
void Buzzer_Init(void)
{
P2SEL &= ~0x01;
P2DIR |= 0x01; //P2_0定义为输出
buzzer = 0;
}
void led_init(void){
P1SEL &= ~0x10;
P1DIR |= 0x10;
LED1 = OFF;
}
三、参考代码
#include<iocc2530.h>
#include<string.h>
#define ECHO P0_0 //ECHO引脚接在P0_0脚
#define TRIG P0_1 //TRIG引脚接在P2_0脚
#define ALARM P2_0 //蜂鸣器P0_1引脚
#define PERIOD 20
#define CYCLE 100
int pulse_high = PERIOD;
unsigned int count_Time; //用于存放计数值
float distance; //存放距离值,float型提高测距精度
unsigned char count_TimeH; //用于存放计数值高8位
unsigned char count_TimeL; //用于存放计数值低8位
char buf[10]; //存放串口发送数据
char info[2]; //存放串口发送数据
/*延时1us函数*/
void delay_1us(int m){
while(m--){
asm("NOP");
asm("NOP");
asm("NOP");
}
}
/*延时1ms函数*/
void delayms(unsigned int ms)
{
unsigned int i, j;
for(i = ms; i > 0; i--)
for(j = 578; j > 0; j--);
}
/*时钟初始化*/
void clk_Init(){
CLKCONCMD &= ~0X40; //设置第6位OSC系统时钟源为32MHZ晶振
while(CLKCONSTA & 0x40); //等待晶振稳定
CLKCONCMD &= ~0x3f; //设置系统主时钟为32MHZ,定时器标记输出设置为32MHZ,时钟速度32MHZ
}
/*串口初始化*/
void usart_Init(){
PERCFG &= ~0x01; //USART0备用位置1
P0SEL |= 0x0c; //P0_2-P0_3为外设
P2DIR &= ~0xc0; //端口0外设优先级配置
U0CSR |= 0X80; //设置为UART模式
U0GCR |= 11; //设置波特率为115200
U0BAUD |= 216;
UTX0IF = 0;
}
/*I/O初始化*/
void io_Init(){
P2SEL &= ~0x01; //P2_0作为通用I/O
P2DIR |= 0X01; //P2_0作为输出口
P0SEL &= ~0x03; //P0_0作为通用I/O
P0DIR &= ~0X01; //P0_0作为输入口
P0DIR |= 0x02;
//P0IF = 0; //清除端口0中断标志
//P0IE = 1; //允许P0口中断
P0IFG = 0x00; //*P0中断标志清零P35
//P0INP &= ~0X00; //*P0_0上拉或下拉
P0IEN |= 0x01; //开启P0_0外部中断
PICTL |= 0x01; //P0下降沿中断
IRCON = 0x00; //设置P0无端口未决
IEN1 |= 0x20; //*设置P0中断使能P38
EA = 1; //*开总中断
}
/*定时器1初始化*/
void timer1_Init(){
T1CTL &= ~0x03; //停止运行
T1CTL |= 0X0c; //设置为128分频
T1CNTH = 0x00;
T1CNTL = 0x00;
}
/*HC_RS04初始化*/
void hc_sr04_Init(){ //20us的声波模块触发信号
TRIG = 1;
delay_1us(20);
TRIG = 0;
while(!ECHO);
T1CTL |= 0x01; //开始自由运行模式
delayms(30);
}
/*串口发送函数*/
void send(char *s){
while(*s!='\0'){
U0DBUF= *s++;
while(UTX0IF == 0); //等待标志位置1,为1时,表示当前字节发送完了
UTX0IF = 0;
}
}
/*P0口中断*/
#pragma vector = P0INT_VECTOR
__interrupt void P0_isr(){
if(P0IFG&0x01){ //判断是否是P0_0中断
T1CTL &= ~0x03; //停止T1运行
P0IF = 0; //清除端口0中断标志
P0IFG &= ~0x01; //清除P0_0中断状态标志
count_TimeH = T1CNTH; //取出定时器 1 计数器高位
count_TimeL = T1CNTL; //取出定时器 1 计数器低位
}
}
int main(){
clk_Init();
io_Init();
usart_Init();
ALARM = 1;
while(1){
timer1_Init(); //定时器初始化
hc_sr04_Init(); //HC_SR04初始化
count_Time = count_TimeH*256+count_TimeL;//计算定时器1计数值
distance = count_Time*0.068; //计算距离
/*将浮点数转为字符串,便于发送(这里只保留了两位小数)*/
if(distance < 100&&distance > 70)
{
while(1)
{
if(P0IFG)
{
ALARM = 1;
break;
}
ALARM=0;
delayms(500);
ALARM=1;
delayms(500);
/*int temp = 1000000;
while(temp--)
{
if (temp % 999999 == 0)
ALARM = 1; // 响1次
else
ALARM = 0;
}*/
}
}
else if(distance <= 70&& distance >40)
{
while(1){
if(P0IFG)
{
ALARM = 1;
break;
}
ALARM = 0;
delayms(100);
ALARM=1;
delayms(100);
/*int temp = 1000000;
while (temp--)
{
if (temp % 499999 == 0)
ALARM = 1; // 响次
else
ALARM = 0;
}
*/
}
}
else if(distance <=40&& distance >=0)
{
while(1){
if(P0IFG)
{
ALARM = 1;
break;
}
/*
int temp = 10000;
while (temp--)
{
ALARM = 1;
}*/
ALARM = 0;
}
}
else
{
ALARM = 1;
}
buf[0] = (unsigned int)distance/100+48;
buf[1] = (unsigned int)distance%100/10+48;
buf[2] = (unsigned int)distance%10+48;
buf[3] = '.';
buf[4] = (unsigned int)(distance*10)%10+48;
buf[5] = (unsigned int)(distance*100)%10+48;
buf[6] = '\n';
send(buf);
memset(buf,0,10); //清空数组
}
}