標(biāo)題:
STM32用GPIO口模擬串口通信的源程序
[打印本頁(yè)]
作者:
wzyan321
時(shí)間:
2018-2-2 17:13
標(biāo)題:
STM32用GPIO口模擬串口通信的源程序
STM32 一般有4、5個(gè)串口,足夠使用,這個(gè)給想擴(kuò)一個(gè)串口的參考
/*
****************************************************************************
* 例程名稱 : Ex004-使用GPIO口模擬串口通信
* 例程版本 : V2.0
* ST固件庫(kù)版本 :V3.5.0
* 作 者 : armfly
* 發(fā)布日期 : 10-16
* 開發(fā)環(huán)境 : KEIL的uVision V3.70、uVision V4.13、IAR的EWARM V5.30
*
* 修改記錄 :
* 2010-09-27 發(fā)布V1.0版本,固件庫(kù)為V3.1.2
* 2011-03-20 發(fā)布V1.1版本,固件庫(kù)為V3.4.0
* 2011-11-16 發(fā)布2.0版本,固件庫(kù)為V3.5.0,優(yōu)化工程結(jié)構(gòu),打印信息改為中文
*
*********************************************************************************************************
*/
【1】例程介紹
這個(gè)例子演示如何使用兩個(gè)GPIO口模擬串口通信,波特率9600,8位數(shù)據(jù)位,1位停止位。
IO口的選擇:
(1)為方便連接至PC的串口,仍選用PA9與PA10,不過這里只將它們當(dāng)作變通的IO口使用。PA9對(duì)應(yīng)TXD,PA10對(duì)應(yīng)RXD的功能。
模擬串口發(fā)送:
(1)TIM3用于產(chǎn)生1bit[104uS]的延時(shí)
模擬串口接收:
(1)PA10上的下降沿將觸發(fā)外部中斷,這標(biāo)志著“起始位0”的到來。在對(duì)應(yīng)的中斷服務(wù)程序中,會(huì)立即關(guān)閉該外部中斷,以
防后續(xù)的“數(shù)據(jù)位”誤觸發(fā)本中斷。
(2)TIM1用于產(chǎn)生104uS的中斷,定時(shí)去讀取PA10上的電平,直至接收到一個(gè)完整的字節(jié)數(shù)據(jù)。
(3)在接收到一個(gè)完整的字節(jié)數(shù)據(jù)之后,開啟TIM2,它的作用是判斷是否接收到了全部的數(shù)據(jù)。
請(qǐng)用串口線將開發(fā)板的COM1口連接到PC機(jī)的串口(或者USB串口),然后打開串口調(diào)試助手(推薦使用作者為聶小猛的那款,它
可以顯示返回至PC的中文字符),可以在軟件界面看到例程的運(yùn)行信息。
程序具有如下功能:
- 復(fù)位后打印例程基本信息
- 在接收完P(guān)C發(fā)送下去的數(shù)據(jù)后,將它們?nèi)糠祷亍?br />
程序執(zhí)行結(jié)果如下:
Hello,C!
*************************************************************
* 例程名稱 : GPIO口模擬串口
* 例程版本 : 1.0
* 發(fā)布日期 : 11-12
* 固件庫(kù)版本 : 3.5.0
*************************************************************
請(qǐng)通過串口調(diào)試助手發(fā)送數(shù)據(jù),本例程會(huì)將這些數(shù)據(jù)通過串口原樣返回。
對(duì)于Keil MDK,為了避免中文字符串告警,需要在C/C++編譯選項(xiàng)中增加 --diag_suppress=870 參數(shù)。
本程序支持在CPU內(nèi)部Flash、CPU內(nèi)部RAM和CPU外部RAM調(diào)試。在CPU內(nèi)部RAM和CPU外部SRAM調(diào)試時(shí),無需切換開發(fā)板上的
啟動(dòng)模式撥碼開關(guān)。請(qǐng)將撥碼開關(guān)撥到Flash位置。
【2】例程文件夾說明
├─Libraries : 存放第3方提供的庫(kù)或其源代碼,這些代碼一般是成熟的并經(jīng)過驗(yàn)證的代碼。
│ ├─CMSIS : Cortex微控制器軟件接口程序,這是ST官方提供的固件庫(kù)的一部分。
│ └─STM32F10x_StdPeriph_Driver : STM32F10x系列MCU的固件庫(kù)源代碼,這是ST官方提供的固件庫(kù)的核心代碼。
│
├─User : 這里存放用戶自己編寫的源代碼
│ └─bsp : 板級(jí)支持包(Board Surport Packet),也就是硬件底層驅(qū)動(dòng)程序
│
└─project : 這里存放各類開發(fā)工具的工程文件
├─EWARMv5 : IAR公司EWARM工程文件
├─MDK-ARM(uV3) :KEIL的MDK工程文件,uVision3版本。uV3不能打開uV4版本的工程。
└─MDK-ARM(uV4) : KEIL的MDK工程文件,uVision4版本。uV4可以打開uV3版本的工程。
【3】工程中源代碼分組說明
└─Flash : Target名稱:Flash、CpuRAM 或 ExtSRAM
├─USER : 用戶程序
├─MDK-ARM : 和IDE開發(fā)工具相關(guān)的啟動(dòng)代碼(匯編)。MDK表示KEIL的IDE,EWARMv5表示IAR的IDE
├─StdPeriph_Driver : STM32F10x系列MCU的固件庫(kù)源代碼
├─CMSIS : Cortex微控制器軟件接口程序源代碼
└─Doc : 存放一些文檔
【4】工程中Target說明
Flash : 目標(biāo)代碼定位在CPU內(nèi)部Flash。ROM地址: 0x08000000 RAM地址: 0x20000000
CpuRAM : 目標(biāo)代碼定位在CPU內(nèi)部RAM。 ROM地址: 0x20000000 RAM地址: 0x20008000
ExtSRAM : 目標(biāo)代碼定位在外部SRAM。 ROM地址: 0x68000000 RAM地址: 0x20000200 (前面0x200空間存放
中斷向量表)
/*
*********************************************************************************************************
*
* 模塊名稱 : 主程序模塊。
* 文件名稱 : main.c
* 版 本 : V1.0
* 說 明 : ADC采樣和濾波例程。
* 修改記錄 :
* 版本號(hào) 日期 作者 說明
*
*********************************************************************************************************
*/
#include "stm32f10x.h" /* 如果要用ST的固件庫(kù),必須包含這個(gè)文件 */
#include <stdio.h> /* 因?yàn)橛玫搅藀rintf函數(shù),所以必須包含這個(gè)文件 */
/* 定義例程名和例程發(fā)布日期 */
#define EXAMPLE_NAME "GPIO口模擬串口"
#define EXAMPLE_DATE "2012-11-12"
#define DEMO_VER "1.0"
#define TXD_high() GPIO_SetBits(GPIOA, GPIO_Pin_9)
#define TXD_low() GPIO_ResetBits(GPIOA, GPIO_Pin_9)
#define BaudRateUsed 9600
#define SendingDelay 104
/* 僅允許本文件內(nèi)調(diào)用的函數(shù)聲明 */
static void PrintfLogo(void);
static void GPIO_Configuration(void);
static void Delay_Ms(__IO uint32_t nTime);
static void EXTI_Configuration(void);
static void TIM1_Configuration(void);
static void TIM2_Configuration(void);
static void TIM3_Configuration(void);
static void PrintfAnswer(void);
/* 外部文件可以調(diào)用的函數(shù)聲明 */
void SendOneByte(uint8_t datatoSend);
__IO uint32_t TimingDelay;
uint8_t dataReceived[100];
uint8_t Logo[]={"Hello, C!\r\n"};
__IO uint8_t receivedFlag;
__IO uint8_t receivedNum, tmpreceivedNum;
uint16_t g_usAdcValue; /* ADC 采樣值的平均值 */
/*
*********************************************************************************************************
* 函 數(shù) 名: main
* 功能說明: c程序入口
* 形 參:無
* 返 回 值: 錯(cuò)誤代碼(無需處理)
*********************************************************************************************************
*/
int main(void)
{
/*
由于ST固件庫(kù)的啟動(dòng)文件已經(jīng)執(zhí)行了CPU系統(tǒng)時(shí)鐘的初始化,所以不必再次重復(fù)配置系統(tǒng)時(shí)鐘。
啟動(dòng)文件配置了CPU主時(shí)鐘頻率、內(nèi)部Flash訪問速度和可選的外部SRAM FSMC初始化。
系統(tǒng)時(shí)鐘缺省配置為72MHz,如果需要更改,可以修改:
\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\system_stm32f10x.c
中配置系統(tǒng)時(shí)鐘的宏。
*/
uint8_t i;
/* IO配置 */
GPIO_Configuration();
/* 配置外部中斷 */
EXTI_Configuration();
/* TIM1初始化,用于接收 */
TIM1_Configuration();
/* TIM2初始化,用于判斷數(shù)據(jù)是否接收完成 */
TIM2_Configuration();
/* TIM3初始化,用于發(fā)送 */
TIM3_Configuration();
/* 直接調(diào)用模擬串口發(fā)送函數(shù) */
SendOneByte('H');
SendOneByte('e');
SendOneByte('l');
SendOneByte('l');
SendOneByte('o');
SendOneByte(',');
SendOneByte('C');
SendOneByte('!');
SendOneByte('\r');
SendOneByte('\n');
/* 打印例程Logo,間接調(diào)用模擬串口發(fā)送函數(shù) */
PrintfLogo();
/* 進(jìn)入主程序循環(huán)體 */
while (1)
{
if(receivedFlag)
{
/* 清除接收完成標(biāo)志位 */
receivedFlag = 0;
/* 返回接收到的數(shù)據(jù) */
for(i = 0; i < tmpreceivedNum; i++)
SendOneByte(dataReceived[i]);
/* 清空接收緩存 */
for(i = 0; i < tmpreceivedNum; i++)
dataReceived[i] = 0;
/* 返回模擬對(duì)話數(shù)據(jù) */
PrintfAnswer();
/* 接收數(shù)據(jù)長(zhǎng)度清零 */
tmpreceivedNum = 0;
}
}
}
/*
*********************************************************************************************************
* 函 數(shù) 名: GPIO_Configuration
* 功能說明: 配置PA9為TXD,PA10做RXD
* 形 參:無
* 返 回 值: 無
*********************************************************************************************************
*/
static void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 使能 GPIOA clock */
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);
/* 防止上電后的誤判 */
GPIO_SetBits(GPIOA, GPIO_Pin_9);
/* 配置PA9為推挽輸出 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 配置PA10為浮空輸入 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/*
*********************************************************************************************************
* 函 數(shù) 名: EXTI_Configuration
* 功能說明: 配置PA10上的下降沿觸發(fā)外部中斷
* 形 參:無
* 返 回 值: 無
*********************************************************************************************************
*/
static void EXTI_Configuration(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the AFIO Clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
/* Configure Button EXTI line */
EXTI_InitStructure.EXTI_Line = EXTI_Line10;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
/* Enable and set Button EXTI Interrupt to the lowest priority */
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/*
*********************************************************************************************************
* 函 數(shù) 名: TIM1_Configuration
* 功能說明: 配置TIM1
* 形 參:無
* 返 回 值: 無
*********************************************************************************************************
*/
static void TIM1_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = SendingDelay -1;
TIM_TimeBaseStructure.TIM_Prescaler = 72-1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
TIM_ClearITPendingBit(TIM1, TIM_FLAG_Update);
/* 開啟TIM1的中斷 */
TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE);
/* 選擇TIM2的中斷通道 */
NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;
/* 搶占式中斷優(yōu)先級(jí)設(shè)置為0 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
/* 響應(yīng)式中斷優(yōu)先級(jí)設(shè)置為0 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
/* 使能中斷 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/*
*********************************************************************************************************
* 函 數(shù) 名: TIM2_Configuration
* 功能說明: 配置TIM1
* 形 參:無
* 返 回 值: 無
*********************************************************************************************************
*/
static void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 1000 - 1;
TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update);
/* 開啟TIM1的中斷 */
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
/* 選擇TIM2的中斷通道 */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
/* 搶占式中斷優(yōu)先級(jí)設(shè)置為0 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 響應(yīng)式中斷優(yōu)先級(jí)設(shè)置為0 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
/* 使能中斷 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/*
*********************************************************************************************************
* 函 數(shù) 名: TIM3_Configuration
* 功能說明: 配置TIM1
* 形 參:無
* 返 回 值: 無
*********************************************************************************************************
*/
static void TIM3_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 65535 - 1;
TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_Cmd(TIM3,ENABLE);
}
/*
*********************************************************************************************************
* 函 數(shù) 名: Delay_Ms
* 功能說明: 延時(shí)
* 形 參:nTime,單位為uS
* 返 回 值: 無
*********************************************************************************************************
*/
void Delay_Ms(__IO uint32_t nTime)
{
uint16_t tmp;
tmp = TIM_GetCounter(TIM3);
if(tmp + nTime <= 65535)
while( (TIM_GetCounter(TIM3) - tmp) < nTime );
else
{
TIM_SetCounter(TIM3, 0);
while( TIM_GetCounter(TIM3) < nTime );
}
}
/*
*********************************************************************************************************
* 函 數(shù) 名: SendOneByte
* 功能說明: 模擬串口發(fā)送一字節(jié)數(shù)據(jù)
* 形 參:無
* 返 回 值: 無
*********************************************************************************************************
*/
void SendOneByte(uint8_t datatoSend)
{
uint8_t i, tmp;
/* Start bit */
TXD_low();
Delay_Ms(SendingDelay);
for(i = 0; i < 8; i++)
{
tmp = (datatoSend >> i) & 0x01;
if(tmp == 0)
{
TXD_low();
Delay_Ms(SendingDelay); //0
}
else
{
TXD_high();
Delay_Ms(SendingDelay); //1
}
}
/* Stop bit */
TXD_high();
Delay_Ms(SendingDelay);
}
/*
*********************************************************************************************************
* 函 數(shù) 名: PrintfLogo
* 功能說明: 打印例程名稱和例程發(fā)布日期, 接上串口線后,打開PC機(jī)的超級(jí)終端軟件可以觀察結(jié)果
* 形 參:無
* 返 回 值: 無
*********************************************************************************************************
*/
static void PrintfLogo(void)
{
printf("*************************************************************\r\n");
printf("* 例程名稱 : %s\r\n", EXAMPLE_NAME); /* 打印例程名稱 */
printf("* 例程版本 : %s\r\n", DEMO_VER); /* 打印例程版本 */
printf("* 發(fā)布日期 : %s\r\n", EXAMPLE_DATE); /* 打印例程日期 */
/* 打印ST固件庫(kù)版本,這3個(gè)定義宏在stm32f10x.h文件中 */
printf("* 固件庫(kù)版本 : %d.%d.%d\r\n", __STM32F10X_STDPERIPH_VERSION_MAIN,
__STM32F10X_STDPERIPH_VERSION_SUB1,__STM32F10X_STDPERIPH_VERSION_SUB2);
printf("* \n\r"); /* 打印一行空格 */
printf("* QQ : 1295744630 \r\n");
printf("* Email : armfly@qq.com \r\n");
printf("* Copyright www.armfly.com 安富萊電子\r\n");
printf("*************************************************************\r\n");
printf("請(qǐng)通過串口調(diào)試助手發(fā)送數(shù)據(jù),本例程會(huì)將這些數(shù)據(jù)通過串口原樣返回。\r\n\r\n");
}
/*
*********************************************************************************************************
* 函 數(shù) 名: PrintfLogo
* 功能說明: 隨機(jī)打印模擬對(duì)話
* 形 參:無
* 返 回 值: 無
*********************************************************************************************************
*/
static void PrintfAnswer(void)
{
uint16_t tmp;
tmp = TIM_GetCounter(TIM3);
switch(tmp % 9)
{
case 0:
printf("\r\n--雷工,數(shù)據(jù)已悉數(shù)返回,掰掰手指頭,有未丟?\r\n");
break;
case 1:
printf("\r\n--報(bào)告雷工,我的工作完了,輪到你檢查了!\r\n");
break;
case 2:
printf("\r\n--咦,還沒有錯(cuò)?\r\n");
break;
case 3:
printf("\r\n--靠,還不出錯(cuò)?\r\n");
break;
case 4:
printf("\r\n--雷工,要不,再試試?\r\n");
break;
case 5:
printf("\r\n--小雷,檢查過沒有,數(shù)據(jù)對(duì)不對(duì)?\r\n");
break;
case 6:
printf("\r\n--小雷,數(shù)據(jù)對(duì)不對(duì)?\r\n");
break;
case 7:
printf("\r\n--怎么樣,小雷,驗(yàn)收通過了沒?\r\n");
break;
case 8:
printf("\r\n--小雷,我的支付寶是168 168 168 168\r\n");
break;
default:
printf("\r\n--這句不可能出現(xiàn)在屏幕上\r\n");
break;
}
}
復(fù)制代碼
源碼下載:
STM模擬串口.7z
(489.86 KB, 下載次數(shù): 319)
2018-2-2 17:12 上傳
點(diǎn)擊文件名下載附件
模擬串口
下載積分: 黑幣 -5
作者:
zjs100
時(shí)間:
2018-2-9 13:23
學(xué)習(xí)一下。。。
作者:
shanz
時(shí)間:
2018-4-22 21:46
很有用
作者:
guo5251
時(shí)間:
2018-6-28 11:01
正需要,學(xué)習(xí)一下
作者:
guo5251
時(shí)間:
2018-6-28 11:25
學(xué)習(xí)一下
作者:
lcg0115
時(shí)間:
2018-7-4 19:49
最近在研究stm,這個(gè)看著很有用,謝謝。
作者:
13481399468
時(shí)間:
2018-7-18 14:55
有毫秒級(jí)的延時(shí)讓單片機(jī)一直在等,不處理任何其它的事情,效率不高,無法用在產(chǎn)品中,玩玩還可以
作者:
飛躍吧
時(shí)間:
2018-12-3 10:25
學(xué)習(xí)一下
作者:
深圳賽易
時(shí)間:
2018-12-3 15:49
感謝分享
作者:
laigs218
時(shí)間:
2018-12-10 20:17
效率不高!但感謝樓主分享
作者:
MiloDai
時(shí)間:
2019-3-10 23:28
感謝提供參考
作者:
280543115
時(shí)間:
2019-3-12 09:03
贊一個(gè)
作者:
失了魂的木偶
時(shí)間:
2019-3-29 09:14
最近在研究這個(gè),學(xué)習(xí)一下
作者:
黑色-眼睛
時(shí)間:
2019-5-7 22:01
謝謝分享,學(xué)習(xí)一下
作者:
適我
時(shí)間:
2019-5-15 17:26
有沒有大神能講講TIM3和延時(shí)函數(shù)那Delay 太懂 Delay函數(shù)里面的 if 。。。while。。。到底怎么形成1us的延時(shí) 然后Delay(104)
作者:
xing1954
時(shí)間:
2019-5-23 20:44
謝謝分享
作者:
fengyehu888
時(shí)間:
2019-7-26 17:01
不錯(cuò),蠻好的,支持樓主
作者:
yyrui
時(shí)間:
2019-8-5 13:26
多謝分享
作者:
pgw00k
時(shí)間:
2019-8-5 17:48
正需要,學(xué)習(xí)一下
作者:
127lo
時(shí)間:
2019-9-2 15:09
感謝
作者:
1336256556
時(shí)間:
2019-10-31 20:03
最近項(xiàng)目需要,正好研究下
作者:
LL_Try123
時(shí)間:
2019-11-21 17:08
可以。能用,易懂
作者:
nuanuan9
時(shí)間:
2019-12-18 14:00
謝謝分享
作者:
RajonRondo
時(shí)間:
2020-3-9 09:38
這個(gè)代碼風(fēng)格 太舒服
作者:
liganchina
時(shí)間:
2020-3-20 11:46
謝謝樓主
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1