7902|17

1634

帖子

0

TA的资源

裸片初长成(高级)

楼主
 

晒一个完整的LM3S811完成的小综合项目,语句详解。 [复制链接]

一个LM3S811的EV板项目,涉及PWM、计数、字符液晶,超声测距,计时采用的是SYSTICK(比TIMER省事),附带时钟显示(简易的,不是32768的RTC)。

接口如下:
PD口接LCD1602的8根数据线;
PB0、1、2分别接LCD1602的RS、RW、E;
PB3、4分别接DYP-ME007超声模块的TRIG、ECHO;
PB6做外部发光二极管指示;
PC5做PWM的输出;
PC6做计数器的输入;
【当然,用PC6计数器接口测量PC5的PWM脉冲(这里只测频率,不测脉宽,不测占空比),所以PC5和PC6要短接】
PB7禁用,以防JTAG锁死。

最后请注意,要在startup.s文件中开通PB引脚中断和定时器1B计数扑捉中断以及SYSTICK计时中断,共三个,如下
extern   SysTick_ISR
extern   Timer1_B_ISR
extern   Int_GPIO_PORTB
//================================================================

//================================================================
/*本实例演示超声模块测距、PWM信号产生、利用计数器测频、利用systick定时作时钟、LCD1602显示*/
#include "lm3sxxx.h"
#define  RS               GPIO_PORTB_BASE,GPIO_PIN_0  //PB0为LCD命令口
#define  RW              GPIO_PORTB_BASE,GPIO_PIN_1  //PB1为LCD命令口
#define  EN               GPIO_PORTB_BASE,GPIO_PIN_2  //PB2为LCD命令口
#define  GPIO_WR    GPIOPinWrite     //简化库函数名
#define  GPIO_RD    GPIOPinRead      //简化库函数名
#define  GPIO_IN      GPIOPinTypeGPIOInput //简化库函数名,周立功中文库函数说明书中居然没有对应的说明
#define  GPIO_OUT   GPIOPinTypeGPIOOutput//简化库函数名,周立功中文库函数说明书中居然没有对应的说明
#define  LCD_DATA   GPIO_PORTD_BASE//lcd数据口
#define  CHAOSHENG_T        GPIO_PIN_3//PB3超声驱动,DYP-ME007是超声模块
#define  CHAOSHENG_R        GPIO_PIN_4//PB4超声状态接收  
#define  LED                          GPIO_PIN_6//PB6计数器捕获指示,每次捕获都取反   
#define  LCD_BUSY                GPIO_PIN_7//PD7数据口第七位测LCD忙
#define  PWM_OUT                GPIO_PIN_5//PC5即CCP1=PWM输出   
#define  COUNT_IN                GPIO_PIN_6//PC6即CCP3=计数输入
#define  PWM_PORT              GPIO_PORTC_BASE
#define  COUNT_PORT           GPIO_PORTC_BASE
#define  LCD_PORT                GPIO_PORTB_BASE//PB0\PB1\PB2给液晶用,PB5未用,PB7给JTAG用,尽量避免作IO
#define  LED_PORT                GPIO_PORTB_BASE//PB6给LED用,秒闪烁
#define  CHAOSHENG_PORT   GPIO_PORTB_BASE//PB3、PB4给超声用
/*=================================================================*/
unsigned long pinlv_vlue=1000;//产生的频率可在这里设置,1MHz误差10%,100KHz误差1.6%,10KHz误差0.1%,1KHz~92Hz没有误差,91以下显示0,没有深入研究。
unsigned long count_vlue=65535;//TIME1B计数器count从最大值开始向下计数
unsigned long systick_vlue=6000000;//6MHz晶振,1s
unsigned char systick_flag,echo_flag=0,count_flag;
unsigned char string1[16]={"    mm        Hz"};  //16个字符
unsigned char string2[16]={"                "};        //16个字符
unsigned long frequency,second=86360;
/*============================延时===============================*/
void delay(unsigned long delay_clok_1us)//1us延时
{
    while(delay_clok_1us)delay_clok_1us--;
}
/*=======================测试LCD忙碌状态=========================*/
unsigned char LCD_check_busy(void)//测试LCD忙碌状态,返回字节型
{
    unsigned char busy;
    GPIO_WR(RS,0);         //RS=0
    GPIO_WR(RW,2);         //RW=1
    GPIO_WR(EN,4);         //EN=1
    GPIO_IN(LCD_DATA , 0XFF);           //设置数据口为输入        
    busy=GPIO_RD(LCD_DATA,LCD_BUSY)&0x80;//读取第八位忙闲标志        
    GPIO_OUT(LCD_DATA,0XFF);             //重新设置数据口为输出
    GPIO_WR(EN, 0);      //EN=0   
    return busy;           //返回检测信号
}
/*================为液晶LCD1602服务的函数===========================*/
void lcd_write(unsigned  char cd,unsigned  char temp)//写入到LCD
{      
    while(LCD_check_busy());//cheker busy
    if(cd)GPIO_WR(RS, 1);   //当写数据时使RS=1
    else  GPIO_WR(RS, 0);   //当为写指令时RS=0      
    GPIO_WR(RW, 0);
    GPIO_WR(EN, 0);
    GPIO_WR(LCD_DATA,0xFF,temp);//送数据到LCD
    GPIO_WR(EN, 4);         //delay(2);//此延时必须要,不然不能显示
    GPIO_WR(EN, 0);      
}
/*================为液晶LCD1602服务的函数===========================*/
void lcd_strwdat( unsigned char x,unsigned char y,unsigned char *str)//准备显示内容
{            
    if(x<16){if(y==0)x=0x80+x;else x=0xc0+x;lcd_write(0,x);}         //显示位置( x, y);
    while(*str!='\0')lcd_write(1,*str++);
}
/*====================定时器1B_count中断===========================*/
void Timer1_B_ISR (void)//定时器1B_count中断处理程序,下降沿触发计数。
{
    TimerLoadSet(TIMER1_BASE, TIMER_B,count_vlue);//重装定时器装载值  
    TimerEnable(TIMER1_BASE, TIMER_B);//使能定时器1B   
    TimerIntClear(TIMER1_BASE, TIMER_CAPB_MATCH);//清除定时器1B中断
    count_flag++;
}
/*====================定时器systick中断,每1秒===========================*/
void SysTick_ISR (void)//systick中断
{ unsigned long temp0;
temp0=TimerValueGet(TIMER1_BASE, TIMER_B);
    TimerLoadSet(TIMER1_BASE, TIMER_B,count_vlue);//重装定时器装载值  
    TimerEnable(TIMER1_BASE, TIMER_B);//使能定时器1B   
GPIO_WR(LED_PORT,LED,GPIO_RD(LED_PORT,LED)^LED);//翻转PB6,指示秒闪烁
temp0=count_vlue-temp0;
frequency=count_flag*count_vlue+temp0;
count_flag=0;   
    systick_flag=1;
}
/*===========液晶的ECHO引脚送入MCUPB4引脚引起GPIO中断服务程序============*/
void Int_GPIO_PORTB(void)  //PB4引脚中断服务程序中,液晶的ECHO引脚送入
{
    echo_flag=1;
    GPIOPinIntClear(CHAOSHENG_PORT, CHAOSHENG_R);//清除引脚中断标志
}
/*=================定时器Timer1B做count计数的初始化init===================*/
void Timer1B_count_init(void)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1 );//使能定时器1外设
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB );//使能GPIOB口外设
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC );//使能GPIOC口外设
    GPIOPinTypeTimer(COUNT_PORT, COUNT_IN);//设置PC6为CCP3功能输入口,做计数器输入口
GPIO_OUT(LED_PORT,LED);//设置 GPIO PB6为输出口,代替GPIODirModeSet(LED_PORT, LED, GPIO_DIR_MODE_OUT)完全可以
GPIO_WR(LED_PORT,LED,0);//点亮LED/
    TimerConfigure(TIMER1_BASE,TIMER_CFG_16_BIT_PAIR|TIMER_CFG_B_CAP_COUNT);//设置定时器1.B为16位定时器配置,边沿计数捕获模式
    TimerControlEvent(TIMER1_BASE,TIMER_B,TIMER_EVENT_NEG_EDGE);//设置为下降沿捕获
    TimerLoadSet(TIMER1_BASE,TIMER_B,count_vlue);//设置定时器装载值为  
    TimerMatchSet(TIMER1_BASE,TIMER_B,0);//设置定时器匹配值   
    TimerIntEnable(TIMER1_BASE, TIMER_CAPB_MATCH);//GPTM捕获B的匹配中断使能
    TimerEnable(TIMER1_BASE, TIMER_B);//使能定时器并开始等待边沿事件   
    IntEnable(INT_TIMER1B);//使能定时器1中断   
}
/*=================定时器Timer0B做PWM的初始化init===================*/
void Timer0B_PWM_init(void)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);//使能定时器0外设
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);//使能GPIOC口外设
    GPIOPinTypePWM(PWM_PORT, PWM_OUT);//设置PC5输出PWM波形
    TimerConfigure(TIMER0_BASE,TIMER_CFG_16_BIT_PAIR|TIMER_CFG_B_PWM);//设置T0B为16-PWMA模式
TimerLoadSet(TIMER0_BASE, TIMER_B,systick_vlue/pinlv_vlue);//pwm_vlue);//设置PWM的装载值
    TimerMatchSet(TIMER0_BASE, TIMER_B,systick_vlue/pinlv_vlue/2);//设置PWM的匹配值 占空比50%
    TimerEnable(TIMER0_BASE, TIMER_B);//PWMA模式使能
}  
/*==========================液晶+超声初始化init=======================*/
void LCD_UltraWave_init(void)//液晶+超声初始化程序
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB|SYSCTL_PERIPH_GPIOD);//端口使能声明
    GPIO_IN(CHAOSHENG_PORT, CHAOSHENG_R);//设置输入引脚(接超声模块ECHO)
    GPIOPinIntEnable(CHAOSHENG_PORT, CHAOSHENG_R);//作为外部引脚中断
    GPIOIntTypeSet(CHAOSHENG_PORT, CHAOSHENG_R, GPIO_RISING_EDGE);//上升沿触发
    IntEnable(INT_GPIOB);//使能PB口中断(仅PC4中断被使能)
SysTickPeriodSet(systick_vlue);//设置SysTick初值,最大为16777216,用于计时
SysTickEnable();     //启动SysTick
    SysTickIntEnable();  //systick系统定时器中断使能     
    GPIO_OUT(LCD_DATA,0xff);//设置LCD数据口(PD)全为输出
    GPIO_OUT(LCD_PORT,0x0f);//设置控制口(PB)低4位(LCD3位,超声模块1位)为输出
    lcd_write(0,0x38); //delay(1);  //八位数据、双行显示、5X7点阵
    lcd_write(0,0x0C); //delay(1);  //显示开、关光标
    lcd_write(0,0x06); //delay(1);  //数据读、写操作后,地址指针AC自动增一
    lcd_write(0,0x01); //delay(1);  //清屏
}
/*==========================主函数=================================*/
main(void) //
{
long i;
    unsigned long j,ulm,ulm0,ulm1,hour,mon;
    SysCtlClockSet(SYSCTL_SYSDIV_1|SYSCTL_USE_OSC|SYSCTL_OSC_MAIN|SYSCTL_XTAL_6MHZ);//系统时钟
    Timer0B_PWM_init();  //PWM初始化  产生PWM波,经CCP1(PC5)输出
Timer1B_count_init();//计数器初始化     检测CCP3(PC6)的脉冲,分频后从PB6输出
    LCD_UltraWave_init();//液晶+超声初始化
    while(1)
{
        if(echo_flag==1)//超声波模块接收到信号的中断标志
        {
/*===========================以下处理测距离数据==========================*/
         echo_flag=0;//中断标志
      ulm0=SysTickValueGet( );//读取SysTic计数值
      i=0;  //i暂时当计时用
         LoopG00:
      j=GPIO_RD(CHAOSHENG_PORT, CHAOSHENG_R);//读出超声波引脚送出的电平
      j=j&CHAOSHENG_R;//第四位00010000B=0x10保留,其余位(还有31位)清零
      i++;  //计时
      if(i>60000)goto LoopG01;//防止超时停机
      if(j==0x10)goto LoopG00;//如果超声波引脚送出的电平还是高电平则转再读引脚
      LoopG01:
      ulm1=SysTickValueGet( );//再次读取计数值
         if(ulm0       ulm=(ulm0-ulm1)/32.32;//计算两次读取SysTick计数值的差所对应的距离
/*========================以下写入测距离数据至数组1=======================*/
      i=3;//先显示最低位在液晶的4位上,后面是mm
      while(i>-1)//左边顶格
      {
          string1[i--]=ulm%10+0x30; //每次都取除10的余数,下一个i--往左移动一位显示
          ulm=ulm/10;         //每次都去掉最低位
      }
        }
/*===================以下为每一个秒钟到达是的事件处理======================*/
  if(systick_flag==1)//systick中断标志,表示又一秒到
  {
      systick_flag=0;
/*===========================以下写入测频数据==============================*/
      i=13;//先显示最低位在液晶的10位上,后面是mm,右边留3个空
      while(i>6)//左边也留3个空
      {
          string1[i--]=frequency%10+0x30; //每次都取除10的余数,下一个i--往左移动一位显示
          frequency=frequency/10;   //每次都去掉最低位
      }
/*===============================以下处理时钟==============================*/
   second++;         //秒数加1
   if(second>86399)second=0;    //一昼夜=86400秒
   hour=second/3600;       //取出小时
   j=second%3600;        //取出去除小时后的秒
   mon=j/60;         //取出分钟
   j=j%60;             //取出秒(临时的)
      i=4;                         //左边空4个,在液晶的第五、六位显示小时
   string2[i++]=hour/10+0x30;  //写入小时的十位
   string2[i++]=hour%10+0x30;  //写入小时的个位
   string2[i++]=':';         //写入":"
   string2[i++]=mon/10+0x30;  //写入分钟的十位
   string2[i++]=mon%10+0x30;  //写入分钟的个位
   string2[i++]=':';           //写入":"
   string2[i++]=j/10+0x30;      //写入秒钟的十位
   string2[i++]=j%10+0x30;      //写入秒钟的个位
/*=====================以下驱动液晶显示==============================*/
      lcd_strwdat(0,0,string1);    //显示第1行
            lcd_strwdat(0,1,string2);    //显示第2行
/*================以下向超声波模块发出驱动电平=======================*/
   GPIO_WR(CHAOSHENG_PORT, CHAOSHENG_T,CHAOSHENG_T);//输出测距模块触发信号为高电平
            delay(13);//高电平延时10us
            GPIO_WR(CHAOSHENG_PORT, CHAOSHENG_T,~CHAOSHENG_T);//输出测距模块触发信号为低电平
       }
    }
}
/*===================================================================*/

最新回复

注释够好,够详细。。。。 对于入门者,肯定是个宝! 如果官方例程都是这样子就好了。  详情 回复 发表于 2013-8-22 15:31

点评

对于入门者,肯定是个宝!  详情 回复 发表于 2012-9-1 23:38

赞赏

1

查看全部赞赏

 
点赞 关注(1)

回复
举报

1万

帖子

25

TA的资源

裸片初长成(高级)

沙发
 

回复 楼主 xu__changhua 的帖子

对于入门者,肯定是个宝!
 
 

回复

1万

帖子

16

TA的资源

版主

板凳
 

恩,写得详细

 
个人签名http://shop34182318.taobao.com/
https://shop436095304.taobao.com/?spm=a230r.7195193.1997079397.37.69fe60dfT705yr
 
 

回复

1万

帖子

16

TA的资源

版主

4
 

恩,写得详细

 
个人签名http://shop34182318.taobao.com/
https://shop436095304.taobao.com/?spm=a230r.7195193.1997079397.37.69fe60dfT705yr
 
 

回复

5015

帖子

12

TA的资源

裸片初长成(初级)

5
 
代码注释的很清楚了
 
 
 

回复

272

帖子

0

TA的资源

一粒金砂(中级)

6
 
顶!!!    注释够好,够详细。。。。
 
 
 

回复

384

帖子

2

TA的资源

纯净的硅(初级)

7
 
MARK
 
 
 

回复

28

帖子

0

TA的资源

一粒金砂(初级)

8
 

好文章

很好,学习了
 
 
 

回复

121

帖子

0

TA的资源

纯净的硅(初级)

9
 
学习了····谢谢分享!
 
 
 

回复

9

帖子

0

TA的资源

一粒金砂(初级)

10
 
好帖啊
 
 
 

回复

1634

帖子

0

TA的资源

裸片初长成(高级)

11
 
上传软件中的附件

DIY.rar

153.3 KB, 下载次数: 8

售价: 2 分芯积分  [记录]

项目中全部文件

 
 
 

回复

1634

帖子

0

TA的资源

裸片初长成(高级)

12
 
实物图片上

811_1602.jpg (153.33 KB, 下载次数: 4)

811_1602.jpg
 
 
 

回复

2万

帖子

71

TA的资源

管理员

13
 
哇  给力 :)
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
个人签名

加油!在电子行业默默贡献自己的力量!:)

 
 

回复

1803

帖子

0

TA的资源

五彩晶圆(高级)

14
 
做的不错
 
 
 

回复

4996

帖子

19

TA的资源

裸片初长成(初级)

15
 
 
个人签名我的博客
 
 

回复

178

帖子

0

TA的资源

一粒金砂(高级)

16
 
值得学习。
 
 
 

回复

22

帖子

2

TA的资源

一粒金砂(中级)

17
 
谢谢楼主的帖子,对于我们新手来说很有帮助啊~
 
 
 

回复

92

帖子

0

TA的资源

一粒金砂(中级)

18
 
注释够好,够详细。。。。 对于入门者,肯定是个宝!
如果官方例程都是这样子就好了。
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表