2015-12-22 14:22:34 u011314012 阅读数 7925
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6012 人正在学习 去看看 朱有鹏
/********该程序主要是利用DS18B20采集温度,然后通过数码管显示温度*************/
/*当程序收到上位机发送的命令之后,该程序会将当时的温度值通过串口发送给上位机*/
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
sbit DQ = P1^0;               //定义DS18B20的信号线端口
uchar i,j;
uchar dis_buffer[4];//定义数据缓冲数组
uchar bit_ser[]={0xfe,0xfd,0xfb,0xf7}; //定义数码管片选数组
uchar seven_seg[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
                                                                    //定义数码管段选数组
/****************************延时函数*********************************/
void delay(uint x)
{
 while(x)   
 x--;
}
/*************************DS18B20初始化函数***************************/
void Init_DS18B20(void)
{
 unsigned char x=0;
 DQ = 1;         //DQ复位
 delay(8);       //稍做延时
 DQ = 0;               //单片机将DQ拉低
 delay(80);     //精确延时 大于 480us
 DQ = 1;           //拉高总线
 delay(14);
 x=DQ;           //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
 delay(20);
}
/***************************从18B20中读一个字节************************/
uchar ReadOneChar(void)
{
 uchar i=0;
 uchar dat = 0;
 for (i=8;i>0;i--)
         {
                 DQ = 0;   // 给脉冲信号
                 dat>>=1;
                 DQ = 1;   // 给脉冲信号
                 if(DQ)
                 dat|=0x80;  
                 delay(8);
         }
         return(dat);
}
/***************************向18B20中写一个字节************************/
Write_OneChar(uchar dat)
{
 uchar i=0;
 for (i=8; i>0; i--)
 {
         DQ = 0;     //给脉冲信号
         DQ = dat & 0x01;
         delay(5); 
         DQ = 1;     //给脉冲信号
         dat >>= 1;
 }
 delay(4);
}
/**************************从18B20中读取一个字节***********************/
int Read_Temperature(void)
{
 uchar i = 0,t = 0,a,b;
 int temp;
 Init_DS18B20();
 Write_OneChar(0xcc);   // 跳过读序号列号的操作
 Write_OneChar(0x44);   // 启动温度转换
 Init_DS18B20();
 Write_OneChar(0xcc);   //跳过读序号列号的操作
 Write_OneChar(0xbe);   //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
 i = ReadOneChar();           //读取温度值低位
 t = ReadOneChar();           //读取温度值高位
 a = i & 0x0f;
 b = t;
 i = i >> 4;             //低位右移4位,舍弃小数部分
 t = t << 4;             //高位左移4位,舍弃符号位
 t = t | i;
 temp = (t + a * 0.0625) * 100; //得到一个比实际温度扩到100倍的值,主要是为了更好的显示和传输          
 return(temp);                  //返回温度值
}

/***************************初始化定时器0******************************/
void timer0_init(void)                      //
{
 TMOD = 0x21; //由于串口通信需要使用定时器1,因此TMOD的值是0x21
 TL0 = (65536-5000) % 256;
 TH0 = (65536-5000) / 256;
 EA = 1;
 ET0 = 1;
 TR0 = 1;
}
/*************************发送数据的函数********************************/
void txd_data(char send_data)    
{
 SBUF = send_data; //将需要发送的数据放入发送缓冲区
 while(!TI);           //等待发送数据
 TI = 0;
}
/********************T0中断处理函数,主要用于显示当前温度***************/
void timer0_isr(void) interrupt 1
{
 int temp; 
 TR0 = 0;
 TL0 = (65536-5000) % 256;
 TH0 = (65536-5000) / 256;
 TR0 = 1;
 switch(i)
 {
         case 0:
                 P2 = bit_ser[0];
                 P0 = seven_seg[dis_buffer[0]];                          
                 break;
         case 1:
                 P2 = bit_ser[1];
                 P0 =seven_seg[dis_buffer[1]] & 0x7f;
                 break;
         case 2:
                 P2 = bit_ser[2];
                 P0 =seven_seg[dis_buffer[2]];
                 break;
         case 3:
                 P2 = bit_ser[3];
                 P0 =seven_seg[dis_buffer[3]];
                 break;
 } 
 i++;
 if(i >= 4) 
 {
         i = 0;
         j++;
         if(j >= 10)  //如果到200ms就会读取一次温度,并将温度值放入显示缓冲区
         {
                 j = 0;
                 temp = Read_Temperature();
                 dis_buffer[0] = temp / 1000;
                 dis_buffer[1] = temp % 1000 / 100;
                 dis_buffer[2] = temp % 100 / 10;
                 dis_buffer[3] = temp % 10;
         }
 }
}

/***************************串口通信初始化函数***************************/
void uart_init(void)
{ 
 SCON = 0x50;         //方式1,充许接收
 TMOD = 0x21;         //T1方式2定时,T0方式是1          
 TH1 = 0xFd;          //波特率9600,Fosc=11.0592MHz
 TL1 = 0xFd;
 TR1 = 1;
 ES = 1;                    // 打开串口中断
}
/**************************串口中断处理函数*****************************/
void uart() interrupt 4                      
{
 char y,i;
 while(!RI);
 y = SBUF;                       //读取接收的信息,然后判断是否为发送温度命令
 if(y == '0')             //如果为发送命令,就将当前数据缓冲数组内的数据发送给上位机
 {
         for(i = 0;i <= 3;i++)
         {
                 txd_data(dis_buffer[i] + 48);
         }
 }
 RI = 0;           
}
/*******************************主函数*********************************/
void main()
{
 timer0_init();           //调用T0初始化函数
 uart_init();             //调用串口初始化函数
 while(1)
 {}
}
2015-06-01 13:40:26 somantek 阅读数 6485
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6012 人正在学习 去看看 朱有鹏

本人最近写了一个单片机与电脑的串口通信程序,程序调试成功,希望对大家有所帮助。本程序的功能有:1、通过DS18B20采集温度并通过1602显示出来。2、单片机与电脑进行通信,上位机给单片机一个读温度指令,单片机把温度值以一定的形式发送给电脑。电脑和单片机的协议如表1所示。 单片机反馈温度值给电脑的形式如表2所示。

表1  电脑读取温度值

 

帧头

帧长度

地址码

保留

功能码

寄存器地址

寄存器个数

 

校验码

 

1字节

1字节

4字节

1字节

1字节

1字节

1字节

1字节

读取温度值

0x01

0x0B

0X00000000

0X00

0X03

0X04

 0x02

0x00

 

表2  单片机反馈温度值给电脑

 

帧头

帧长度

地址码

保留

功能码

寄存器地址

寄存器个数

数据

 

校验码

 

1字节

1字节

4字节

1字节

1字节

1字节

1字节

4字节

1字节

环境值

0x01

0x0F

0X00000000

0X00

0X03

0X04

 0x02

0X00 0X00 0X00 0X01

0x00

    其中单片机反馈温度的数据形式为:共有三字节数据(从数据区第二个字节开始算),分别为十位、个位、十分位,其中十位的BIT7表示温度正负,BIT7=0,表示为正值,BIT7=1,表示为负值,温度数值采用扩展BCD码表示;

例: 

0x00,0x03,0x01,0x05表示+31.5℃

   0x00,0x81,0x02,0x05表示-12.5℃

串口通讯程序的编写采用的是C语言编写。单片机接收是通过中断来接收                  的,每收到一个字节的数据就产生一次中断,并在中断处理程序中把接收到的内容保存在数组中,这样就可以接收多个字节的数据。因为要向电脑发送多个字节的内容,所以单片机的发送采用循环发送的方式,通过循环把一帧数据发送出去。具体程序如下所示。

1602头文件:

/*-----------------------------------------------

名称:LCD1602

引脚定义如下:1-VSS 2-VDD 3-V0 4-RS 5-R/W 6-E 7-14 DB0-DB7 15-BLA       16-BLK

------------------------------------------------*/

#include "1602.h"

#include "delay.h"

 

sbit RS = P1^6;   //定义端口 

sbit RW = P1^5;

sbit EN = P1^4;

 

#define RS_CLR RS=0 

#define RS_SET RS=1

 

#define RW_CLR RW=0 

#define RW_SET RW=1 

 

#define EN_CLR EN=0

#define EN_SET EN=1

 

#define DataPort P2

 

/*------------------------------------------------

              判忙函数

------------------------------------------------*/

 bit LCD_Check_Busy(void) 

 { 

 DataPort= 0xFF; 

 RS_CLR; 

 RW_SET; 

 EN_CLR; 

 _nop_(); 

 EN_SET;

 return (bit)(DataPort & 0x80);

 }

/*------------------------------------------------

              写入命令函数

------------------------------------------------*/

 void LCD_Write_Com(unsigned char com) 

 {  

 while(LCD_Check_Busy()); //忙则等待

 RS_CLR; 

 RW_CLR; 

 EN_SET; 

 DataPort= com; 

 _nop_(); 

 EN_CLR;

 }

/*------------------------------------------------

              写入数据函数

------------------------------------------------*/

 void LCD_Write_Data(unsigned char Data) 

 { 

 while(LCD_Check_Busy()); //忙则等待

 RS_SET; 

 RW_CLR; 

 EN_SET; 

 DataPort= Data; 

 _nop_();

 EN_CLR;

 }

 

/*------------------------------------------------

                清屏函数

------------------------------------------------*/

 void LCD_Clear(void) 

 { 

 LCD_Write_Com(0x01); 

 DelayMs(5);

 }

/*------------------------------------------------

              写入字符串函数

------------------------------------------------*/

 void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s) 

 {     

 if (y == 0) 

  {     

 LCD_Write_Com(0x80 + x);     //表示第一行

  }

 else 

  {      

  LCD_Write_Com(0xC0 + x);      //表示第二行

  }        

 while (*s) 

  {     

 LCD_Write_Data( *s);     

 s ++;     

  }

 }

/*------------------------------------------------

              写入字符函数

------------------------------------------------*/

 void LCD_Write_Char(unsigned char x,unsigned char y,unsigned char Data) 

 {     

 if (y == 0) 

  {     

  LCD_Write_Com(0x80 + x);     

  }    

 else 

  {     

  LCD_Write_Com(0xC0 + x);     

  }        

 LCD_Write_Data( Data);  

 }

/*------------------------------------------------

              初始化函数

------------------------------------------------*/

 void LCD_Init(void) 

 {

   LCD_Write_Com(0x38);    /*显示模式设置*/ 

   DelayMs(5); 

   LCD_Write_Com(0x38); 

   DelayMs(5); 

   LCD_Write_Com(0x38); 

   DelayMs(5); 

   LCD_Write_Com(0x38);  

   LCD_Write_Com(0x08);    /*显示关闭*/ 

   LCD_Write_Com(0x01);    /*显示清屏*/ 

   LCD_Write_Com(0x06);    /*显示光标移动设置*/ 

   DelayMs(5); 

   LCD_Write_Com(0x0C);    /*显示开及光标设置*/

   }

/*------------------------------------------------   

设定二个自定义字符,LCD1602中自定义字符的地址为0x00--0x07,

即可定义8个字符

这里我们设定把一个自定义字符放在0x00位置(000),

另一个放在0x01位子(001)

------------------------------------------------*/

void Lcd_User_Chr(void)

{ //第一个自定义字符

 LCD_Write_Com(0x40); //"01 000 000"  第1行地址 (D7D6为地址设定命令形式D5D4D3为字符存放位置(0--7),D2D1D0为字符行地址(0--7))

 LCD_Write_Data(0x00); //"XXX 11111" 第1行数据(D7D6D5为XXX,表示为任意数(一般用000),D4D3D2D1D0为字符行数据(1-点亮,0-熄灭)

 LCD_Write_Com(0x41); //"01 000 001"  第2行地址

 LCD_Write_Data(0x04); //"XXX 10001" 第2行数据

 LCD_Write_Com(0x42); //"01 000 010"  第3行地址

 LCD_Write_Data(0x0e); //"XXX 10101" 第3行数据

 LCD_Write_Com(0x43); //"01 000 011"  第4行地址

 LCD_Write_Data(0x0e); //"XXX 10001" 第4行数据

 LCD_Write_Com(0x44); //"01 000 100"  第5行地址

 LCD_Write_Data(0x0e); //"XXX 11111" 第5行数据

 LCD_Write_Com(0x45); //"01 000 101"  第6行地址

 LCD_Write_Data(0x1f); //"XXX 01010" 第6行数据

 LCD_Write_Com(0x46); //"01 000 110"  第7行地址

 LCD_Write_Data(0x04); //"XXX 11111" 第7行数据

 LCD_Write_Com(0x47); //"01 000 111"  第8行地址

   LCD_Write_Data(0x00); //"XXX 00000" 第8行数据 

 //第二个自定义字符

 

 LCD_Write_Com(0x48); //"01 001 000"  第1行地址  

 LCD_Write_Data(0x03); //"XXX 00001" 第1行数据 

 LCD_Write_Com(0x49); //"01 001 001"  第2行地址

 LCD_Write_Data(0x03); //"XXX 11011" 第2行数据

 LCD_Write_Com(0x4a); //"01 001 010"  第3行地址

 LCD_Write_Data(0x00); //"XXX 11101" 第3行数据

 LCD_Write_Com(0x4b); //"01 001 011"  第4行地址

 LCD_Write_Data(0x00); //"XXX 11001" 第4行数据

 LCD_Write_Com(0x4c); //"01 001 100"  第5行地址

 LCD_Write_Data(0x00); //"XXX 11101" 第5行数据

 LCD_Write_Com(0x4d); //"01 001 101"  第6行地址

 LCD_Write_Data(0x00); //"XXX 11011" 第6行数据

 LCD_Write_Com(0x4e); //"01 001 110"  第7行地址

 LCD_Write_Data(0x00); //"XXX 00001" 第7行数据

 LCD_Write_Com(0x4f); //"01 001 111"  第8行地址

 LCD_Write_Data(0x00); //"XXX 00000" 第8行数据 

 }

DS18B20头文件:

/*-----------------------------------------------

  名称:18B20温度传感器

  内容:18B20单线温度检测的应用样例程序

------------------------------------------------*/

#include"delay.h"

#include"18b20.h"

/*------------------------------------------------

                    18b20初始化

------------------------------------------------*/

bit Init_DS18B20(void)

{

 bit dat=0;

 DQ = 1;    //DQ复位

 DelayUs2x(5);   //稍做延时

 DQ = 0;         //单片机将DQ拉低

 DelayUs2x(200); //精确延时 大于 480us 小于960us

 DelayUs2x(200);

 DQ = 1;        //拉高总线

 DelayUs2x(50); //15~60us 后 接收60-240us的存在脉冲

 dat=DQ;        //如果x=0则初始化成功, x=1则初始化失败

 DelayUs2x(25); //稍作延时返回

 return dat;

}

 

/*------------------------------------------------

                    读取一个字节

------------------------------------------------*/

unsigned char ReadOneChar(void)

{

unsigned char i=0;

unsigned char dat = 0;

for (i=8;i>0;i--)

 {

  DQ = 0; // 给脉冲信号

  dat>>=1;

  DQ = 1; // 给脉冲信号

  if(DQ)

   dat|=0x80;

  DelayUs2x(25);

 }

 return(dat);

}

/*------------------------------------------------

                    写入一个字节

------------------------------------------------*/

void WriteOneChar(unsigned char dat)

{

 unsigned char i=0;

 for (i=8; i>0; i--)

 {

  DQ = 0;

  DQ = dat&0x01;

  DelayUs2x(25);

  DQ = 1;

  dat>>=1;

 }

DelayUs2x(25);

}

 

/*------------------------------------------------

                    读取温度

------------------------------------------------*/

unsigned int ReadTemperature(void)

{

unsigned char a=0;

unsigned int b=0;

unsigned int t=0;

Init_DS18B20();

WriteOneChar(0xCC); // 跳过读序号列号的操作

WriteOneChar(0x44); // 启动温度转换

DelayMs(10);

Init_DS18B20();

WriteOneChar(0xCC); //跳过读序号列号的操作 

WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度

a=ReadOneChar();   //低位

b=ReadOneChar();   //高位

 

b<<=8;

t=a+b;

 

return(t);

}

延迟函数头文件:

#include "delay.h"

/*------------------------------------------------

 uS延时函数,含有输入参数 unsigned char t,无返回值

 unsigned char 是定义无符号字符变量,其值的范围是

 0~255 这里使用晶振12M,精确延时请使用汇编,大致延时

 长度如下 T=tx2+5 uS 

------------------------------------------------*/

void DelayUs2x(unsigned char t)

{   

 while(--t);

}

/*------------------------------------------------

 mS延时函数,含有输入参数 unsigned char t,无返回值

 unsigned char 是定义无符号字符变量,其值的范围是

 0~255 这里使用晶振12M,精确延时请使用汇编

------------------------------------------------*/

void DelayMs(unsigned char t)

{

     

 while(t--)

 {

     //大致延时1mS

     DelayUs2x(245);

 DelayUs2x(245);

 }

}

主函数:

/*-----------------------------------------------

  名称:DS18b20 温度检测 LCD1602液晶显示 与上位机串口通信

------------------------------------------------*/

    #include<reg52.h> //包含头文件,一般情况不需要改动             #include<stdio.h>

#include "18b20.h"

#include "1602.h"

#include "delay.h"

bit ReadTempFlag;//定义读时间标志

char jsdata[16]={0};

char fsdata[16]={0};

char receive_end=0;

char i=0;

void Init_Timer0(void);//定时器初始化

/*------------------------------------------------

              串口通讯初始化

------------------------------------------------*/

void com_init(void) //设置串口调试助手的波特率为9600

{

    TMOD=0X20;

    SCON=0X50;

TH1=0XFD;

TL1=0XFD;

TR1=1;

EA=1;//总中断打开

ES=1; //串口中断打开,等待接收和发送中断

}

/*------------------------------------------------

                    主函数

------------------------------------------------*/

void main (void)

{                  

int temp,j;

float temperature;

char displaytemp[16];//定义显示区域临时存储数组

RI=0;

com_init(); 

LCD_Init();           //初始化液晶

DelayMs(20);          //延时有助于稳定

LCD_Clear();          //清屏

Init_Timer0();

Lcd_User_Chr();       //写入自定义字符

LCD_Write_String(0,0,"15.5.15");

LCD_Write_Char(14,0,0x01);//写入温度右上角点

LCD_Write_Char(15,0,'C'); //写入字符C

while (1)         //主循环

  {

 

        if(ReadTempFlag==1)

          {

            ReadTempFlag=0;

            temp=ReadTemperature();

            temperature=(float)temp*0.0625;

            sprintf(displaytemp,"%7.3f",temperature);//打印温度值 

            LCD_Write_String(7,0,displaytemp);

//SBUF=temperature;

          }

         if(receive_end==1)    

  { 

    receive_end=0;             

if(temperature>0)

  {

    fsdata[0]=0x01;

    fsdata[1]=0x0F;

    fsdata[2]=0X00;

fsdata[3]=0X00;

fsdata[4]=0X00;

fsdata[5]=0X00;

fsdata[6]=0X00;

  fsdata[7]=0X03;

fsdata[8]=0X04;

fsdata[9]=0x02;

fsdata[10]=0X00;

fsdata[11]=temperature/10;

fsdata[12]=((int)temperature)%10;

fsdata[13]=(((int)(temperature*10))%100)%10;

fsdata[14]=0x00;

for(j=0;j<15;j++)

   {

 SBUF=fsdata[j];

 while(!TI);

  TI=0;

}

    }

 if(temperature<0)

   {

fsdata[0]=0x01;

    fsdata[1]=0x0F;

    fsdata[2]=0X00;

fsdata[3]=0X00;

fsdata[4]=0X00;

fsdata[5]=0X00;

fsdata[6]=0X00;

fsdata[7]=0X03;

fsdata[8]=0X04;

fsdata[9]=0x02;

fsdata[10]=0X00;

fsdata[11]=((int)temperature/10)|0x80;

fsdata[12]=((int)temperature)%10;

fsdata[13]=(((int)(temperature*10))%100)%10;

fsdata[14]=0x00;

for(j=0;j<15;j++)    

   {    

 SBUF=fsdata[j];

 while(!TI);

 TI=0;

   }

   }

 }

 }

}

 

/*------------------------------------------------

                    定时器初始化子程序

------------------------------------------------*/

void Init_Timer0(void)

{

 TMOD |= 0x01;   //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响      

 //TH0=0x00;       //给定初值

 //TL0=0x00;

 EA=1;            //总中断打开

 ET0=1;           //定时器中断打开

 TR0=1;           //定时器开关打开

}

/*------------------------------------------------

                 定时器中断子程序

------------------------------------------------*/

void Timer0_isr(void) interrupt 1 

{

 static unsigned int num;

 TH0=(65536-2000)/256;   //重新赋值 2ms

 TL0=(65536-2000)%256;

 num++;

 if(num==300)        

   {

    num=0;

    ReadTempFlag=1; //读标志位置1

}

}

/*------------------------------------------------

             串口中断中断服务子程序

------------------------------------------------*/

void jieshou() interrupt 4

  {

    if(RI==1)

      {   

    RI=0; 

jsdata[i]=SBUF;

i++;

if((i==11)&&(jsdata[i-4]==0x03))

      {

    i=0;

receive_end=1;//接收完成标志置1 

  }

  }   

 }

串口调试界面如下图所示,只要上位机发送一个读取温度指令,单片机就以一定的格式发送一帧温度数据给上位机。

 

 

2019-01-13 22:05:42 Tee1234 阅读数 299
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6012 人正在学习 去看看 朱有鹏

                                           3    Zigbee 的串口和ADC

1  CC2530使用的电平是TTL电平

2.电脑从usb口出来是232电平

3.电脑和单片机的电平是不同的,所以需要PL2303转换电平

4.波特率的计算

5.串口的收,以及串口发

现象1:发给串口

现象2:串口的发送

5.ADC——检测CC2530内部温度——程序步骤123

6.不知道怎么出现了这个错误,重新加了.c   .h又可以了

Error[e46]: Undefined external "UART_SendString::?relay" referred in adc ( G:zigbee new studyledDebugObjadc.r51 ) 

7.adc测量cc2530芯片内部的温度,新看到的   memset(TX_BUF,0,5);   这个函数

#include <stdio.h>
#include <string.h>
#include "uart.h"

char TX_BUF[5];   //发送缓冲区

void Set_32MHZ(void)
{
  CLKCONCMD&=~0x40;  //系统时钟晶振为32M,OSC位置0
 while(CLKCONSTA & 0x40);  //等待时钟稳定,1为16M的RC振荡
  CLKCONCMD&=~0x47;  //32M
}

//延时函数
void delay_ms(uint16 n_ms)
{
  uint16 i,j;
  for(i=0; i<(n_ms*2); i++)  //本实验采用的32M HZ,所以乘以2
  {
    for(j=0; j<535; j++);
  }
}
//初始化cc2530内部温度传感器
void Sensor_init(void)
{
  IEN0=IEN1=IEN2=0X00;  //关闭所有中断
  TR0 =0x01;  //连接温度传感器到SOC_ADC
  ATEST=0X01;  //使能温度传感器
}
//ADC初始化
void ADC_init(void)
{
  ADCCON3=0X3e;  //512抽取率(12位ENOB——有效位),温度传感器;
  ADCCON1|=0X30; //手动开启模式;0011 0000
  ADCCON1|=0X40;  //1时开启AD转换;  0100 0000
}
//获取温度
float GetTemperature(void)
{
  unsigned int value;
  ADC_init();
  while(!(ADCCON1&0x80));//等待转换完成;
  
  value=ADCL>>4;  //ADCL是ADC转换结果的数据低位
  value|=(((unsigned int)ADCH)<<4);  //ADCH是ADC转换结果的数据高位
  
  return (value-1367.5)/4.5-5;  //根据实际AD值计算得4.5为温度系数,5为温度校正(芯片不同,值不同)
  
}

void main()
{
    unsigned char i;
    float AvgTem;
    
    Set_32MHZ();   //初始化系统时钟:32MHZ
    UART_Init();   //初始化串口;
    Sensor_init(); //初始化芯片内部温度传感器
    
    while(1)
    {
       AvgTem = 0;
       
       for(i = 0; i < 21; i++) //获取10次温度值的平均值;
       {
            if(i > 10) //排除前几次可能出现不稳定的情况;
            {
                AvgTem += GetTemperature();
                AvgTem /= 2;
            }
       }
       
       memset(TX_BUF,0,5);
       sprintf(TX_BUF,"%.02f",AvgTem); //浮点数转换成字符串;
       UART_SendString(TX_BUF,5);     //串口打印温度值;
       UART_SendString("\r\n",2); 
       
       delay_ms(1000);
    }
}

 

 

2017-07-28 12:35:56 Horizonhui 阅读数 432
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6012 人正在学习 去看看 朱有鹏

  该例程是基于MSP430单片机,利用430单片机内部的温度传感器将数据传到连接在单片机的433M无线模块上,然后由无线模块将数据发送出去,发送至连接在PC机上的433M,由C语言程序将433M的信息(包含通信协议)读取并且写入一个txt文件,代替串口调试助手。

  附上MSP430的程序

#include <msp430x14x.h>
#include "Config.h"                     //????????,????IO????  
ulong temp;
ulong TemperF;                             //????
ulong TemperC;    
//***********************************************************************
//               MSP430IO初始化
//***********************************************************************
uchar i = 0;
//端口的初始化
void Port_init()
{
        P6SEL = 0x00;
        P6DIR = 0xff;                 //输出状态
	P4SEL = 0x00;
        P4DIR = 0xFF;                   //???????
        P5SEL = 0x00;
        P5DIR|= BIT5 + BIT6 + BIT7;     //??????????
}
void Send_Byte(uchar data)
{
  while(!(IFG1&UTXIFG0));          //?????????????
    U0TXBUF=data;
}

//*************************************************************************
//               MSP430串口的初始化
//*************************************************************************
void UART_Init()
{
  U0CTL|=SWRST + CHAR;                //??SWRST,8?????
  U0TCTL|=SSEL1;                      //SMCLK?????
  U0BR1=baud_h;                       //BRCLK=8MHZ,Baud=BRCLK/N
  U0BR0=baud_l;                       //N=UBR+(UxMCTL)/8
  U0MCTL=0x00;                        //??????0,???9600bps
  ME1|=UTXE0;                         //UART0????
  ME1|=URXE0;                         //UART0????
  U0CTL&=~SWRST;
  IE1|=URXIE0;   
  
  
 /* U1CTL|=SWRST + CHAR;                //??SWRST,8?????
  U1TCTL|=SSEL1;                      //SMCLK?????
  U1BR1=baud_h;                       //BRCLK=8MHZ,Baud=BRCLK/N
  U1BR0=baud_l;                       //N=UBR+(UxMCTL)/8
  U1MCTL=0x00;                        //??????0,???9600bps
  ME2|=UTXE1;                         //UART0????
  ME2|=URXE1;                         //UART0????
  U1CTL&=~SWRST;
  IE2|=URXIE1;   */   
  P3SEL|= BIT4 + BIT5;                //??IO????????,??UART??
  P3DIR|= BIT4;                       //??TXD0??????
}
//接收中断
#pragma vector=UART0RX_VECTOR
__interrupt void UART0_RX_ISR(void)
{
  uchar data;
  data=U0RXBUF; 
  P6OUT = data;
}
//*************************************************************************
//	ADC初始化函数
//*************************************************************************
void ADC_Init()
{
  P6SEL|=0x01;                                    //??ADC??
  ADC12CTL0|= ADC12ON + SHT0_2 + REF2_5V + REFON; //ADC?????,16?CLK,????2.5V
  ADC12CTL1|= ADC12SSEL1 + ADC12SSEL0;            //SMCLK????
  ADC12MCTL0= SREF0 + INCH_0;                     //??????????,??????0
  ADC12IE|= 0x01;                                 //????
  ADC12CTL0|= ENC;                                //?????
}

//*************************************************************************
//	ADC中断程序
//*************************************************************************
#pragma vector=ADC_VECTOR
__interrupt void ADC12ISR(void) {
   temp = ADC12MEM0;         //保存转换结果
}

void Print_Str(uchar *s)
{
    while(*s != '\0')
    {
        Send_Byte(*s++);
    }
}
//*************************************************************************
//     主函数
//*************************************************************************
void main(void)
{ 
    WDT_Init();   //看门狗设置
    UART_Init();
    Clock_Init();                                     //系统时钟设置
    Port_init();                                      //系统初始化,设置IO口属性
    delay_ms(100);                                    //延时100ms
    ADC12CTL0 = SHT0_8 + REFON + ADC12ON;              //内部1.5V参考电压,打开ADC12模块,设置采样保持定时器
    ADC12CTL1 = SHP;                                   //采使用采样定时器
    ADC12MCTL0 = SREF_1 + INCH_10;                     //参考电压和通道选择
    ADC12IE = BIT0;                                    //ADC12MEM0
    ADC12CTL0 |= ENC;                                  //允许转换

    _BIS_SR(GIE);                                      //开启系统中断

    while(1) 
    {
        ADC12CTL0 |= ADC12SC;                          //开始采样并AD转换

        //oF = ((x/4096)*1500mV)-923mV)*1/1.97mV = x*761/4096 - 468
        //IntDegF = (ADC12MEM0 - 2519)* 761/4096
        TemperF = (temp - 2519) * 761;
        TemperF = TemperF / 4096;                      //简化的华氏温度转换公式

        //oC = ((x/4096)*1500mV)-986mV)*1/3.55mV = x*423/4096 - 278
        //IntDegC = (ADC12MEM0 - 2692)* 423/4096
        TemperC = (temp - 2692) * 423;
        TemperC = TemperC / 4096;                      //简化的摄氏温度转换公式
        Send_Byte('!');                                //编写简单的通信协议,避免不同的433M之间数据接收混乱
        Send_Byte('!');
        Send_Byte('!');
        Send_Byte(TemperC/10+0x30);
        Send_Byte(TemperC%10+0x30);
        Send_Byte('C');
        Send_Byte(' ');
        Send_Byte('#');                                结束标志
        delay_ms(1500);
        _NOP();                                        //加入断点可用来观察TemperF和TemperC结果
    }
}

接着是C语言读取串口的C语言程序:

#include <stdio.h>
#include <windows.h>
FILE * fileFP;
int main(void)
{
   FILE *fp;
   char temp;
   int count = 0, cnt = 0;
   //char buf[100];
   if((fp=fopen("com3", "r")) == NULL) puts("can't open the com/n");
   if((fileFP=fopen("testdata.txt", "w")) == NULL) puts("can't open the file/n");
   while(1)
   {
      temp = 0;
      fscanf(fp, "%c", &temp);
      if(temp == '!')                      //判断协议  
      	count++;
     if(temp == '#')
     	{
     		count = 0;
     		cnt++;                    // 接收数据计数
     	}
      if(count == 3&&temp != '!')
      {
         putchar(temp);
         fprintf(fileFP, "%c", temp);
      }
      else
      	Sleep(100);
     if(cnt >= 5){                       //设置每次读取五个数据
      	break;
      }
   }

   	fclose(fp);                      //关闭文件以及串口
        fclose(fileFP);
   return 0;
}


2014-12-30 14:18:26 wenwenxixi 阅读数 4647
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6012 人正在学习 去看看 朱有鹏
自己做的一个单片机和手机进行的蓝牙通讯,想和巴友们一起分享,希望大家支持。谢谢~(非常适用于毕业设计-基于蓝牙的温度采集系统)
先给大家大致讲下我做的这个的内容:
    实现功能就是在单片机上接上蓝牙的从机模块和温度传感器以及液晶显示屏,手机呢我自己写了一个界面(有实现蓝牙打开、搜索和连接其他蓝牙设备、接收和发送数据),单片机在温度传感器测出温度后将值通过蓝牙模块发给手机蓝牙(串口通讯原理)并在手机设计的界面显示,手机上我也做了个与单片机交互的一个小功能,就是在手机上发一串信息出去,然后单片机接收并显示到液晶屏。
PS:上面所讲单片机,我用的是51(其他单片机也类似的)。然后除了采集温度,也可采集湿度啊、PM2.5啊、紫外线强度啊等等扥等、、、
如果有什么问题可以联系这个QQ进行一起交流:974135698 谢谢~~~

GY-39连接52单片机

阅读数 105

vc串口通信

阅读数 2250

没有更多推荐了,返回首页