第一次来,发点东西,就当到此一游。
KEIL5, c++, 103c8t6 多个软串口类。
理论上能支持多个串口,但实际我只同时测试了2个,频率测试过9600和19200。
多个串口同时接收数据时,会有数据冲突的时候,后端加验证应该能解决。
========================================================
需要建立6个文件:
myfun.h,myfun.cpp,exint.h,exint.cpp,serial.h,serial.cpp
========================================================
myfun.h文件内容:
#ifndef __MYFUN__
#define __MYFUN__
#include <STM32f10x.h>
void delay_nop(u16 n=1);
void Inittimer();
void delay(u16 =1);
void delay_us(u32=1);
class PORT{
public:
GPIO_TypeDef* GPIO;
uint16_t Pin;
PORT();
PORT(GPIO_TypeDef*,uint16_t);
void Low();
void High();
void setMode(GPIOMode_TypeDef);
u8 Read();
u8 PortNo;
u8 PinNo;
};
#endif
==============================================
myfun.cpp内容:
#include "myfun.h"
u16 __fac_us,__fac_ms;
void InitTimer(){
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCLK/8
__fac_us=SystemCoreClock/8000000; //为系统时钟的1/8
__fac_ms=(u16)__fac_us*1000;
}
void delay(u16 ms){
while(ms--) {delay_us(1000);}
}
void delay_us(u32 nus){
if (nus<1) return;
u32 temp;
SysTick->LOAD=nus*__fac_us; //时间加载
SysTick->VAL=0x00; //清空计数器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL =0X00;
}
void delay_nop(u16 n) {
while(0
}
PORT::PORT(){};
PORT::PORT(GPIO_TypeDef* gpio,uint16_t pin){
if (gpio==GPIOA) PortNo=0;
if (gpio==GPIOB) PortNo=1;
if (gpio==GPIOC) PortNo=2;
GPIO=gpio;
Pin=pin;
PinNo=0;
while(!((Pin>>PinNo) & 0x1)) PinNo++;
}
void PORT::Low() {
GPIO->BRR =Pin;
}
void PORT::High() {
GPIO->BSRR =Pin;
}
void PORT::setMode(GPIOMode_TypeDef mode) {
GPIO_InitTypeDef gpio;
//uint32_t rcc=(u32)RCC_APB2Periph_GPIOA;
//rcc=rcc<
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA<
/*
if (GPIO==GPIOA) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
if (GPIO==GPIOB) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
if (GPIO==GPIOC)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
*/
gpio.GPIO_Pin=Pin;
gpio.GPIO_Mode=mode;
gpio.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIO,&gpio);
}
u8 PORT::Read() {
return GPIO_ReadInputDataBit(GPIO,Pin);
//return (GPIO->IDR & Pin);
}
======================================================
exint.h内容:
#ifndef __MYEXINT__
#define __MYEXINT__
#include
class EXINT{
public:
EXINT();
bool Init(PORT,u16);
void CompleIRQ();
void Read(u8 *buf);
u16 count;
private:
PORT RX;
u8 BUF[128];
u16 delaytime;
};
extern "C" {
void CompleEXINT(u8);
bool InitEXTI(PORT,void*());
void EXTI0_IRQHandler(void);
void EXTI1_IRQHandler(void);
void EXTI2_IRQHandler(void);
void EXTI3_IRQHandler(void);
void EXTI4_IRQHandler(void);
void EXTI9_5_IRQHandler(void);
void EXTI15_10_IRQHandler(void);
}
#endif
==========================================
exint.cpp内容:
#include "EXINT.h"
#include "stm32f10x.h"
#define FUNMAXCOUNT 2
u8 EXTI_FUN_COUNT[16];
EXINT *EXTI_FUN[16*FUNMAXCOUNT];
u8 __EXINTINITED;
EXINT::EXINT() {}
bool EXINT::Init(PORT p,u16 dt) {
delaytime=dt;
RX=p;
uint8_t irq;
//根据Pin 判断使用哪个中断
if (RX.PinNo<5)
irq=EXTI0_IRQn+RX.PinNo;
else if (RX.PinNo<10)
irq=EXTI9_5_IRQn;
else
irq=EXTI15_10_IRQn;
//判断是否还可以再放中断程序
u8 c=EXTI_FUN_COUNT[RX.PinNo];
if (c>=FUNMAXCOUNT) return false;//超5个不能再放了
EXTI_FUN[16*c+RX.PinNo]=this;
EXTI_FUN_COUNT[RX.PinNo]++;
if (!__EXINTINITED) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启IO复用时钟
__EXINTINITED=true;
}
if (EXTI_FUN_COUNT[RX.PinNo]<2) {
//设置IO口与中断线的映射关系
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA + p.PortNo ,GPIO_PinSource0+RX.PinNo);
//GPIO_EXTILineConfig(GPIO_PortSourceGPIOB ,GPIO_PinSource8);
EXTI_InitTypeDef exti;
exti.EXTI_Line=EXTI_Line0<
//exti.EXTI_Line=EXTI_Line2;
exti.EXTI_Mode=EXTI_Mode_Interrupt;
exti.EXTI_Trigger=EXTI_Trigger_Falling; //设置触发方式
exti.EXTI_LineCmd=ENABLE; //开启
EXTI_Init(&exti);
//EXTI_GetITStatus(u32_t Exti_line); //判断中断状态,是否发生
NVIC_InitTypeDef nvic;
//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
nvic.NVIC_IRQChannel=irq; //EXTI0_IRQn;
//nvic.NVIC_IRQChannel=EXTI9_5_IRQn; //EXTI0_IRQn;
nvic.NVIC_IRQChannelSubPriority=RX.PinNo; //中断优先级
nvic.NVIC_IRQChannelPreemptionPriority=15;
nvic.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&nvic);
EXTI_ClearITPendingBit(EXTI_Line0<
//EXTI_ClearITPendingBit(EXTI_Line2);
}
return true;
};
void EXINT::Read(u8 *buf){
u8 i=0;
u8 c=count;
count=0;
while(c--) {
buf=BUF;
i++;
}
buf=0;
}
void EXINT::CompleIRQ() {
//EXTI->IMR &=1<
u8 i=8;
u8 data=0;
while(i--) {
delay_us(delaytime);
data >>=1;
if (RX.Read()) data |=0x80;
}
//delay_us(delaytime);
BUF[count]=data;
count++;
//等待停止位
i=delaytime;
while(i--) {
if (RX.Read()) return;
}
if (count>=128) count=0;
//EXTI->IMR |=1<
EXTI_ClearITPendingBit(EXTI_Line0<
}
extern "C" {
void CompleEXINT(u8 n) {
/*u8 EXTI_FUN_COUNT[7]={0};
void* EXTI_FUN[7][5]={0};*/
u8 c=EXTI_FUN_COUNT[n];
u8 i;
for(i=0;i
EXINT *e=EXTI_FUN[16*i+n];
e->CompleIRQ();
}
}
void EXTI0_IRQHandler(void) {
CompleEXINT(0);
}
void EXTI1_IRQHandler(void) {
CompleEXINT(1);
}
void EXTI2_IRQHandler(void) {
CompleEXINT(2);
}
void EXTI3_IRQHandler(void) {
CompleEXINT(3);
}
void EXTI4_IRQHandler(void) {
CompleEXINT(4);
}
void EXTI9_5_IRQHandler(void) {
if (EXTI_GetITStatus(EXTI_Line5)!=RESET) CompleEXINT(5);
if (EXTI_GetITStatus(EXTI_Line6)!=RESET) CompleEXINT(6);
if (EXTI_GetITStatus(EXTI_Line7)!=RESET) CompleEXINT(7);
if (EXTI_GetITStatus(EXTI_Line8)!=RESET) CompleEXINT(8);
if (EXTI_GetITStatus(EXTI_Line9)!=RESET) CompleEXINT(9);
}
void EXTI15_10_IRQHandler(void) {
if (EXTI_GetITStatus(EXTI_Line10)!=RESET) CompleEXINT(10);
if (EXTI_GetITStatus(EXTI_Line11)!=RESET) CompleEXINT(11);
if (EXTI_GetITStatus(EXTI_Line12)!=RESET) CompleEXINT(12);
if (EXTI_GetITStatus(EXTI_Line13)!=RESET) CompleEXINT(13);
if (EXTI_GetITStatus(EXTI_Line14)!=RESET) CompleEXINT(14);
if (EXTI_GetITStatus(EXTI_Line15)!=RESET) CompleEXINT(15);
}
}
===================================================
serial.h内容:
#ifndef __MYSERIAL__
#define __MYSERIAL__
#include
#include "exint.h"
class SERIAL {
public:
SERIAL(u32=9600);
void Init(PORT,PORT,u32=9600);
u16 getCount();
void Read(u8 *buf);
void WriteBuf(u8*,u16);
void Write(u8);
PORT RX,TX;
private:
void Read();
u16 Speed;
u8 ReadData;
EXINT exint;
};
#endif
==============================================
#include "serial.h"
#include "exint.h"
SERIAL::SERIAL(u32 speed) {
float s=speed;
s=1/s*1000*1000;
Speed=s;
}
void SERIAL::Init(PORT rx,PORT tx,u32 speed) {
float s=speed;
s=1/s*1000*1000;
Speed=s;
RX=rx;TX=tx;
TX.setMode(GPIO_Mode_Out_PP);
TX.High();
RX.setMode(GPIO_Mode_IPU);
exint.Init(RX,Speed);
}
u16 SERIAL::getCount() {
return exint.count;
}
void SERIAL::Read(u8 *buf) {
exint.Read(buf);
}
void SERIAL::WriteBuf(u8 *buf,u16 len) {
u8 i=0;
while(len--) {
Write(buf);
i++;
}
}
void SERIAL::Write(u8 data) {
u8 i=8;
TX.Low();
delay_us(Speed);
while(i--) {
data&0x01?TX.High():TX.Low();
delay_us(Speed);
data>>=1;
}
TX.High();
delay_us(Speed);
}
=================================================
=================================================
main 中引用上面的库
使用方法:
SERIAL s //先定义个串口.
s.Init(PORT(GPIOB,GPIO_Pin_8),PORT(GPIOB,GPIO_Pin_9));
//上面是初始化RX和TX,波特率默为是9600,如果要改,Init第三个参数是波特率。
u8 buf[128]={0}; //定义接收/发送的缓存
u8 c; //保存串口数据个数
while(1) {
if (c=s.getCount()) {
//如果串口里有数据
//TurnLED(true); 这里可以点亮LED灯
s.Read(buf); //就读到缓存
//delay(10); TurnLED(false);这里延时10ms,后关闭LED灯,用于数据传输提示
s.WriteBuf(buf,c); //将接收到的数据,发送回去。
}
}
===========END 2018/4/20=======================================
|