久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 1912|回復: 2
打印 上一主題 下一主題
收起左側

51單片機串口使用入門

[復制鏈接]
跳轉到指定樓層
樓主
深入串口@[通信](這里寫自定義目錄標題)

# 串口通信簡介

你好! 如果這是你第一次使用 **串口** ,那么了解一些串口是什么以及怎么用吧。

## 串口是什么

一般來說,單片機與上位機之間以串口通信為主,就串口通信而言。常用的幾種通信方式,包括串口自定義協議、Modbus協議、CAN總線。重點介紹一下串口通信。


## IDEA想法
現在小銘有一臺電腦和一個外設,現在他想讓外設給電腦發送一個字母A。怎么辦呢?我們知道計算機的世界只有0和1。那么用0和1怎么發送A甚至是任意數據呢?

假設我們每次發送一個字節那么它要么是0要么是1,接下來我們一次發送8個字節則依然是每一位為0或者1。但是注意到
也就是說第一位可以代表1個數字,第二位代表2個數字......第八位可以代表128個數字,那么這八個字節可以代表1+2+4+8+16+32+64+128=255個數字。如果對照ASCII表基本上可以發送所有字符。
## 通信
好了,現在我們按照ASCII上對應關系開始發送數據吧。還是以A為例。A對應的十進制是65。    65=1+64。那么我們可以讓第一位是1,第7位也是1,其他位為0。
現在我們已經成功的發送了A。
  此外還得規定通信速率也就是波特率每秒發送的位數。這里就不詳細介紹了。

## 單片機實現串口通信
    51單片機
要想使用串口就要了解一下兩個寄存器和定時器。
(1)串口控制寄存器 SCONSCON=0x40  工作方式1;0100  0000  串口不接受數據

SCON=0x50  工作方式1;0101  0000   串口接受數據

(2)電源控制寄存器 PCON

PCON=0X80;波特率加倍

PCON=0X00;波特率不加倍

(3)TMOD   計數器這什么玩意?要不我們換一張圖看看吧!

```c
TMOD|=0X20; //設置計數器工作方式 2
TH1=baud; //計數器初始值設置
TL1=baud
```


2)
```c
TMOD|=0X01;//選擇為定時器 0 模式,工作方式1  
TH0=初值
TL0=初值
```
## 硬核知識-串口發送字節
了解完以上內容現在我們就可以寫一個串口發送的函數了。我們定義函數為uart_init()
在這個函數里我們做這幾件事情:
①確定 T1 的工作方式(TMOD 寄存器);
②確定串口工作方式(SCON 寄存器);
③計算 T1 的初值(設定波特率),裝載 TH1、TL1;
④啟動 T1(TCON 中的 TR1 位);
⑤如果使用中斷,需開啟串口中斷控制位(IE 寄存器)。
如果你要實現不同的功能那么這個初始化的函數也會不一樣。這里我們寫幾個典型的例子:
**實現功能**:串口把接收到的數據發送回單片機
```c
void uart_init(void)
{
TMOD|=0X20; //設置計數器工作方式 2
SCON=0X50; //設置為工作方式 1
PCON=0X80; //波特率加倍 4800倍后為9600
TH1=0XFA; //計數器初始值設置
TL1=OXFA;
ES=1; //打開接收中斷
EA=1; //打開總中斷
TR1=1; //打開計數器
}

void uart() interrupt 4//串口通信中斷函數
{
u8 rec_data;
RI = 0; //清除接收中斷標志位
rec_data=SBUF; //存儲接收到的數據
SBUF=rec_data; //將接收到的數據放入到發送寄存器
while(!TI); //等待發送數據完成
TI=0; //清除發送完成標志位
}



**串口功能**:發送傳感器數據,無需中斷


void UART_Init(void)
{
SCON=0x50;                        //串口通信工作方式1
TMOD=0x20;                //定時器1的工作方式2
PCON=0X00;      //不加倍
TH1=0xfd,TL1=0xfd;        //9600baud        
TI=1;            //這里一定要注意
TR1=1;

}
//如果你有一個返回ADC的函數adc_value()
float buff;
buff=adc_value();
printf("data is %f",buff);
//你就可以成功的把數據在串口助手中顯示了

這里我重點介紹一下printf函數
printf   打印調試把數據顯示在串口助手中或者是oled屏幕上。
配合上面那個串口初始化函數,然后在頭文件中包含#Include “stdio.h”就可以使用了。


printf("welcome to the digatal world");

但是使用printf唯一的不好就是如果要與上位機通信它發送的數據位數不一樣;比如說你的數據是3.23;45.13;100.64;數據位數不一樣在于上位機通信時會給軟件編程造成很大的麻煩。最好是003.23;045.13;100.64;怎么做到呢?小白我編程能力有限,如果有大佬會請留言謝謝!
下面介紹用**寄存器**收發數據。

void UART_Init(void)
{
        
        TMOD|=0X20;        //設置計數器工作方式2
        SCON=0X50;        //設置為工作方式1
        PCON=0X00;        //波特率加倍
        TH1=0xfd;        //計數器初始值設置
        TL1=0xfd;
        ES=1;                //打開接收中斷
        EA=1;                //打開總中斷
        TR1=1;                //打開計數器        
}
void UART_Sendchar(unsigned char d)                  //發送一個字節的數據,形參d即為待發送數據。
{
         SBUF=d; //將數據寫入到串口緩沖
        while(!TI);
        TI=0;
}
void UART_SendString(unsigned char *String)
{
    while(*String)
    {
        UART_Sendchar(*String);
        String++;
    }
}
UART_Sendchar(65);        //發送A十進制對應的符號是A
UART_Sendchar('a');//發送a 注意只能單引號
UART_Sendchar(0x65);//發送e十六進制65對應的符號是e
UART_SendString("小七");//發送字符串
/*****在這里你應該理解了吧串口發送就是按照ASCII表的規則來的。無論你發的是十進制還是十六進制最后都會轉換成對應的符號

//發送浮點數
float b=3.2;//帶轉化數據
uchar conver_t[4];//一定要定義成**數組**類型
float b=3.2;
sprintf(conver_t,"%f",b);//通過%.1f /%.2f可以改變小數位數
UART_SendString(conver_t);


## 串口接收中斷的設置;一般用于上位機控制


**根據接受的數據做出響應,如燈的翻轉,之類的**。
直接上代碼!

//串口控制led亮滅
#include "reg52.h"
#include "stdio.h"
sbit  led=P1^5;
unsigned char rec;

void receive_dat( rec)
{
        if(rec==0x00)
        {
                led=0;
        }
        else if(rec==0x01)
        {
                 led=1;
        }
        else if(rec==0x02)
        {
                led=0;
        }
        else
        {
                led=1;
        }
}
void UART_Sendchar(unsigned char d)                  //發送一個字節的數據,形參d即為待發送數據。
{
         SBUF=d; //將數據寫入到串口緩沖
        while(!TI);
        TI=0;
}
void uart_init(void)
{
TMOD|=0X20; //設置計數器工作方式 2
SCON=0X50; //設置為工作方式 1
PCON=0X00; //波特率加倍 4800倍后為9600
TH1=0XFd; //計數器初始值設置
TL1=0xfd;
TR1=1; //打開計數器;
ES=1;                //打開串口中斷
EA=1;                //打開總中斷
TR1=1;                //打開計數器
ET1=0;        
}

void  main()
{
   uart_init();
   UART_Sendchar('E');
        while(1)
        {
        }
}

void Uart() interrupt 4
{
         if(RI==1)
{   RI=0;
        rec=SBUF;
        receive_dat(rec);                          
}
        }

注意,本代碼不是萬能!如果你的程序很簡單那么這些代碼基本沒問題,但是小白我就曾經遇到了一個問題。我在一個項目中用到了兩個中斷,定時器、串口中斷沖突。結果接收上位機的數據相關代碼一直不起作用。我以為是串口接收中斷函數有問題。在網上查了一下,可能的原因很多。解決辦法嘛主流的是增加中斷時間,然后還有一個就是改中斷號優先級。我都嘗試過對我的程序來說沒有用。最后無意中在一個帖子看到降低串口波特率。我把9600改為4800后果然有用。遇到問題,多去查查。幾十億人,他們就做的全都對嘛?也會有類似的問題對吧。
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏4 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:562099 發表于 2024-5-26 17:31 | 只看該作者
正好看這方面資料。注解很詳細,分析很到位。
回復

使用道具 舉報

板凳
ID:961114 發表于 2024-5-30 09:10 | 只看該作者
可以去看免費視頻講解  
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 欧美国产精品久久久 | 亚洲国产成人精品一区二区 | 日韩中文字幕免费在线 | 日韩免费视频 | 国产精久久久久久久 | 国产99免费视频 | 青草久久免费视频 | 中文字幕精品一区二区三区精品 | 草久在线视频 | 久草中文在线 | 亚洲黄色网址视频 | 91网站在线播放 | 中文字幕精品一区二区三区精品 | 欧美一区二区久久 | av手机在线| 三级成人在线 | 中文字幕在线观看一区 | 在线观看av网站永久 | 国产精品波多野结衣 | 最新日韩精品 | 欧美三级视频 | 国产一区二区三区精品久久久 | 国产成人精品一区二区在线 | 久久免费福利 | 国产精品综合色区在线观看 | 一区二区三区视频在线观看 | 国产羞羞视频在线观看 | 波多野结衣在线观看一区二区三区 | 亚洲免费一区二区 | 国产精品久久久久9999鸭 | 天天天操天天天干 | 九九热这里只有精品在线观看 | 91精品欧美久久久久久久 | 日韩在线免费视频 | 日韩黄a | 91免费在线 | 欧美午夜一区二区三区免费大片 | 激情久久久久 | 第四色播日韩第一页 | 国产乱性 | 成人免费视频在线观看 |