目标:
通过自定义通信协议,达到以串口发送指令,使STM32单片机能够根据指令控制继电器的通断时间,从而方便开关机的实验。
上位机的使用方法:
自定义通信协议( ee 00 12 04 ff)
ee:帧数据的头部
00 12:十六进制数 --》十进制为18 则代表导通时间为18s
04:继电器的断开时间十进制为4 则代表为断开时间为4s
ff:帧的尾部
注意:
在输入数据时,输入ee的头部不能出现空格。
在未输入指令时,系统默认导通60s,断开4s;
在输入指令时导通时间需至少2s,断开时间需至少2s。
注意单片机板卡是否支持USB转TTL电路;
先插入USB再启动上位机软件。
第一部分:完成上位机的编写
#ifndef RELAYSYS_H
#define RELAYSYS_H
#include <QWidget>
#include <QSerialPort> //提供访问串口的功能
#include <QSerialPortInfo> //提供系统中存在的串口信息
#include <qtimer.h>
#include <QDebug>
#include <QStringList>
#include <QMessageBox>
#include <QTextBlock>
namespace Ui {
class RelaySys;
}
class RelaySys : public QWidget
{
Q_OBJECT
public:
explicit RelaySys(QWidget *parent = 0);
~RelaySys();
void serialPortInit(void); //串口初始化
char convertCharToHex(char ch);
int QString2HexInt(QString str);
private slots:
void on_pushButton_OpenSerial_clicked();
void on_pushButton_send_clicked(); //发送按钮槽函数
void on_serialPortRecv(void); //串口接收槽函数
void on_timeUpData(void);
void on_pushButton_clearRecv_clicked();
void on_pushButton_clearSend_clicked();
private:
Ui::RelaySys *ui;
QSerialPort *serial; //创建串口对象
QTimer *timer = new QTimer(); //创建定时器,用于在规定的时间内对接收到的数据进行处理
bool flag = true;
QByteArray buf; //接收串口发送过来的数据
int sendBuffer[5];
};
#endif // RELAYSYS_H
源文件
#include "relaysys.h"
#include "ui_relaysys.h"
RelaySys::RelaySys(QWidget *parent) :
QWidget(parent),
ui(new Ui::RelaySys)
{
ui->setupUi(this);
this->setWindowTitle("继电器控制软件");
serial = new QSerialPort;
serialPortInit();
//连接信号槽函数,当下位机发送数据QSerialPortInfo会发送readRead信号
connect(serial,SIGNAL(readyRead()),this,SLOT(on_serialPortRecv()));
connect(timer,SIGNAL(timeout()),this,SLOT(on_timeUpData()));
}
RelaySys::~RelaySys()
{
delete serial;
delete ui;
}
void RelaySys::serialPortInit()
{
foreach (const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
{
ui->comboBox_port->addItem(info.portName());//添加串口号名字
serial->setPort(info);
}
#if 1
QStringList baudList;
QStringList checkList;
QStringList dataBitList;
QStringList stopBitList;
baudList << "4800" << "9600" << "14400" << "19200"
<< "38400"<< "56000"<< "57600" << "115200";
ui->comboBox_baud->addItems(baudList);
ui->comboBox_baud->setCurrentIndex(7);
checkList << "No" << "Even" << "Odd" << "Space" << "Mark";
ui->comboBox_check->addItems(checkList);
ui->comboBox_check->setCurrentIndex(0);
dataBitList << "5 bit" << "6 bit" << "7 bit" << "8 bit";
ui->comboBox_dataBit->addItems(dataBitList);
ui->comboBox_dataBit->setCurrentIndex(3);
stopBitList << "1 bit" << "1.5 bit" << "2 bit";
ui->comboBox_stopBit->addItems(stopBitList);
ui->comboBox_stopBit->setCurrentIndex(0);
#else
//增加波特率下拉框选项
ui->comboBox_baud->addItem("4800");
ui->comboBox_baud->addItem("9600");
ui->comboBox_baud->addItem("14400");
ui->comboBox_baud->addItem("19200");
ui->comboBox_baud->addItem("38400");
ui->comboBox_baud->addItem("56000");
ui->comboBox_baud->addItem("57600");
ui->comboBox_baud->addItem("115200");
//默认选择第7个115200这个波特率
ui->comboBox_baud->setCurrentIndex(7);
//增加数据位下拉框选项
ui->comboBox_dataBit->addItem("5");
ui->comboBox_dataBit->addItem("6");
ui->comboBox_dataBit->addItem("7");
ui->comboBox_dataBit->addItem("8");
ui->comboBox_dataBit->setCurrentIndex(3);
//增加停止位下拉框选项
ui->comboBox_stopBit->addItem("1 bit");
ui->comboBox_stopBit->addItem("1.5 bit");
ui->comboBox_stopBit->addItem("2 bit");
ui->comboBox_stopBit->setCurrentIndex(0);
ui->comboBox_check->addItem("NONE");
/*
ui->comboBox_port->clear();
//获取可连接的所有的串口的名字
QList<QSerialPortInfo>serialportInfos = QSerialPortInfo::availablePorts();
qDebug()<< "Total numbers of ports:"<<serialportInfos.count();
//用于循环访问serialportInfos集合中所需要的信息
foreach (const QSerialPortInfo info,serialportInfos)
{
ui->comboBox_port->addItem(info.portName());//添加串口号名字
}
*/
#endif
}
void RelaySys::on_pushButton_OpenSerial_clicked()
{
qDebug() << ui->pushButton_OpenSerial->text() << endl;
if(ui->pushButton_OpenSerial->text() == "打开")
{
serial->setPortName(ui->comboBox_port->currentText()); //设置串口名
if(!serial->open(QIODevice::ReadWrite))//用ReadWrite的模式尝试打开串口
{
QMessageBox::about(NULL,"提示","串口打开\r\n不存在或被其它程序占用");
qDebug() << "打开失败!" << endl;
return;
}
else
{
qDebug()<< endl << "打开成功" << endl;
//设置波特率
serial->setBaudRate(ui->comboBox_baud->currentText().toInt());
//设置校验位
switch(ui->comboBox_check->currentIndex())
{
case 0: serial->setParity(QSerialPort::NoParity);break;
case 1: serial->setParity(QSerialPort::EvenParity);break;
case 2: serial->setParity(QSerialPort::OddParity);break;
case 3: serial->setParity(QSerialPort::SpaceParity);break;
case 4: serial->setParity(QSerialPort::MarkParity);break;
default: break;
}
//设置数据位
switch(ui->comboBox_dataBit->currentIndex())
{
case 0: serial->setDataBits(QSerialPort::Data5);break;
case 1: serial->setDataBits(QSerialPort::Data6);break;
case 2: serial->setDataBits(QSerialPort::Data7);break;
case 3: serial->setDataBits(QSerialPort::Data8);break;
default: break;
}
//设置停止位
switch(ui->comboBox_stopBit->currentIndex())
{
case 0: serial->setStopBits(QSerialPort::OneStop);break;
case 1: serial->setStopBits(QSerialPort::OneAndHalfStop);break;
case 2: serial->setStopBits(QSerialPort::TwoStop);break;
default: break;
}
//设置流控
serial->setFlowControl(QSerialPort::NoFlowControl);
ui->comboBox_baud->setEnabled(false);
ui->comboBox_check->setEnabled(false);
ui->comboBox_dataBit->setEnabled(false);
ui->comboBox_port->setEnabled(false);
ui->comboBox_stopBit->setEnabled(false);
ui->pushButton_OpenSerial->setText("关闭");
}
}
else
{
if(serial->isOpen()) //如果串口打开则将其关闭
{
serial->clear();
serial->close();
}
ui->pushButton_OpenSerial->setText("打开");
ui->comboBox_baud->setEnabled(true);
ui->comboBox_check->setEnabled(true);
ui->comboBox_dataBit->setEnabled(true);
ui->comboBox_port->setEnabled(true);
ui->comboBox_stopBit->setEnabled(true);
qDebug() << "关闭成功" << endl;
}
}
void RelaySys::on_pushButton_send_clicked()
{
int i = 0;
short value = 0; //记录导通的有效时间
int SIZE = 0; //接收个数
char *pBuf = (char *)&value;
QString temp;
//获取textEdit中的内容 toPlainText()获取文本函数
QString str = ui->textEdit->toPlainText();
QStringList list = str.split(" ");//以指定的字符“ ”空格分割支付串
SIZE = sizeof(sendBuffer)/sizeof(sendBuffer[0]);
//qDebug() << "SIZE = " << SIZE;
if(list.length() > SIZE && list[SIZE] != NULL)
{
QMessageBox::about(NULL, "提示", "请输入有效的指令!");
return ;
}
for(i = 0; i < SIZE; i++)
{
temp = list[i];
if(temp.length() > 2 || temp.length() == 1 )
{
QMessageBox::about(NULL, "提示", "请输入有效的指令!");
return ;
}
sendBuffer[i] = QString2HexInt(temp); //转化为十进制
/*sendBuffer[i] = temp.toInit(&ok,16);*/
qDebug() << sendBuffer[i] << " ";
}
pBuf[0] = sendBuffer[2];
pBuf[1] = sendBuffer[1];
//qDebug() << "value == " << value << endl;
//对帧数据进行校验
if(list[0] != "ee" || value < 2 || sendBuffer[3] < 2 || list[4] != "ff")
{
QMessageBox::about(NULL, "提示", "输入的指令不正确,请重新输入;格式: ee 导通时间>=2s 断开时间>=2s ff");
return ;
}
else
{
QByteArray buffer;
buffer.resize(SIZE);
for(int i = 0; i < SIZE; i++)
{
buffer[i] = sendBuffer[i];
}
serial->write(buffer);
}
}
void RelaySys::on_timeUpData(void)
{
timer->stop();
//时间到了处理数据
}
void RelaySys::on_serialPortRecv(void)
{
timer->start(100); //使用定时器定时接收数据,非阻塞机制,100ms后自动认为接收数据完成
//buf = serial->readAll();
buf.append(serial->readAll());
int i = 0;
QString RecvBuffer; //存放十六进制数据
QString st; //使能够显示中文
QString str;
if(!buf.isEmpty()) //若非空则表示有数据接收
{
st = QString::fromLocal8Bit(buf); //需能显示中文
qDebug() << "st = " << st << endl;
if(ui->checkBox_show16->isChecked())
{
str = buf.toHex().data(); //转换成十六进制
str = str.toUpper(); //转换成大写
for(i = 0; i < str.length(); i += 2)
{
QString temp = str.mid(i, 2);
RecvBuffer += temp;
RecvBuffer += " ";
}
ui->plainTextEdit->appendPlainText(RecvBuffer);
}
else
{
ui->plainTextEdit->appendPlainText(st);
}
}
QString line = QString::number(ui->plainTextEdit->document()->lineCount());
// QMessageBox::information(this,"information",line);
int line_val = line.toInt();
qDebug() << "line = " << line_val;
// QString data = ui->plainTextEdit->document()->findBlockByLineNumber(line_val).text();
//qDebug() << "data = " << data;
buf.clear();
}
//将一个字节的字符串转化为整型 十六进制转化为十进制 如“0x1f"--->31
int RelaySys::QString2HexInt(QString str)
{
QByteArray byte;
byte = str.toLatin1(); //单字节编码兼容ASCII
int high = convertCharToHex(byte[0]);
int low = convertCharToHex(byte[1]);
return high*16 + low;
}
char RelaySys::convertCharToHex(char ch)
{
if((ch >= '0') && (ch <= '9'))
return ch - 0x30; //0x30 -->48
else if((ch >= 'A') && (ch <= 'F'))
return ch - 'A' +10;
else if((ch >= 'a') && (ch <= 'f'))
return ch - 'a' + 10;
else
return -1;
}
void RelaySys::on_pushButton_clearRecv_clicked()
{
ui->plainTextEdit->clear();
}
void RelaySys::on_pushButton_clearSend_clicked()
{
ui->textEdit->clear();
}
第二部分:关于keil的工程创建及功能实现
main.c
#include "main.h"
#include "core_cm0.h"
#include "relay.h"
#include "usart.h"
#include "delay.h"
#include "TIM_delay.h"
extern uint8_t gRecvBuff[5];
extern uint8_t gRecvFlag;
extern uint32_t gCount;
void SysTick_Delay_Ms( __IO uint32_t ms)
{
uint32_t i;
SysTick_Config(SystemCoreClock/1000);
for(i=0;i<ms;i++)
{
// 当计数器的值减小到0的时候,CRTL寄存器的位16会置1
// 当置1时,读取该位会清0
while( !((SysTick->CTRL)&(1<<16)) );
}
// 关闭SysTick定时器
SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk;
}
void SYSTICK_INIT(void)
{
SysTick_Config(SystemCoreClock / 1000); //Set SysTick Timer for 1ms interrupts
//SysTick_Config(SystemCoreClock / 200); //Set SysTick Timer for 5ms interrupts
//SysTick_Config(SystemCoreClock / 100); //Set SysTick Timer for 10ms interrupts
//SysTick_Config(SystemCoreClock / 10); //Set SysTick Timer for 100ms interrupts
}
void delay(int num)
{
unsigned int i = 0;
while(num--)
{
for(i = 0; i < 1650; i++);
}
}
/**
* @brief Main program
* @param None
* @retval None
*/
int main(void)
{
uint8_t i = 0;
uint16_t num = 0;
uint8_t *pBuf = (uint8_t *)#
uint16_t OnTimes = 0;
uint32_t tempCnt = gCount;
USART_Config(115200);
delay_init();
TIMx_Init(999,47);
relay_init();
// printf("format: 0xEE 0xMS1 0xMS0 0xFF \n");
// delay_ms(10);
// printf("ms1:导通时间,ms0:断开时间\n");
loop:
while (1)
{
if(gRecvFlag == 0) //未收到指令时,默认是导通60s,断开4s
{
relay_on();
OnTimes++;
printf("Times = %d\n",OnTimes);
for(i = 0; i < 60; i++)
{
if(gCount == 1) //若第一条指令到来,退出默认状态 关闭导通
{
//printf("gCount = %d\n",gCount);
tempCnt = gCount;
relay_off();
OnTimes = 0;
delay_ms(1000); //不加延时无法看出新指令执行效果
break;
}
delay_ms(1000);
}
relay_off();
for(i = 0; i < 4; i++)
{
if(gCount == 1) //若第一条指令到来则,退出默认状态
{
tempCnt = gCount;
relay_off();
OnTimes = 0;
delay_ms(1000);
break;
}
delay_ms(1000);
}
}
else
{
while(!gRecvFlag); //收到指令
// for(i = 0; i < 4; i++)
// {
// printf("gRecvBuff[%d] = %x\n",i,gRecvBuff[i]);
// }
relay_on();
OnTimes++;
printf("Times = %d\n",OnTimes);
pBuf[0] = gRecvBuff[2];
pBuf[1] = gRecvBuff[1];
//printf("0x%02x \n",num);
for( i = 0; i < num; /* i < gRecvBuff[1]*10; */ i++)
{
if(tempCnt + 1 == gCount)
{
//printf("tempCnt = %d\n",tempCnt);
tempCnt = gCount; //tempCnt++;
relay_off();
OnTimes = 0;
delay_ms(2000);
goto loop;
}
delay_ms(1000);
}
relay_off();
for( i = 0; i < gRecvBuff[3]; i++)
{
if(tempCnt + 1 == gCount)
{
tempCnt = gCount; //tempCnt++;
relay_off();
OnTimes = 0;
delay_ms(2000);
goto loop;
}
delay_ms(1000);
}
}
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
while (1)
{
}
}
#endif
relay.h
#ifndef RELAY_H_
#define RELAY_H_
#include "stm32f0xx.h"
void relay_init(void);
void relay_on(void);
void relay_off(void);
#endif /* RELAY_H_*/
relay.c
#include "relay.h"
void relay_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); //时钟配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽模式输出
//GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //无上下拉(浮空)
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_SetBits(GPIOB, GPIO_Pin_11);
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
void relay_on(void)
{
GPIO_SetBits(GPIOB,GPIO_Pin_2);
//GPIOB->BSRR = GPIO_Pin_2;
GPIO_ResetBits(GPIOB, GPIO_Pin_11);
}
void relay_off(void)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_2);
//GPIOB->BRR = GPIO_Pin_2;
GPIO_SetBits(GPIOB, GPIO_Pin_11);
}
delay.h
#ifndef DELAY_H_
#define DELAY_H_
#include "stm32f0xx.h"
#include "core_cm0.h"
void delay_init(void);
void delay_us(uint32_t nus);
void delay_ms(uint32_t nms);
void Delay_ms(uint32_t nms);
void Delay_us(uint32_t nus);
#endif /*DELAY_H_*/
delay.c
#include "delay.h"
static uint8_t fac_us=0; //us延时倍乘数
static uint16_t fac_ms=0; //ms延时倍乘数,在ucos下,代表每个节拍的ms数
//查询方式
void delay_init(void)
{
//SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCLK/8
SysTick->CTRL = 0xFFFFFFFB;
fac_us = SystemCoreClock / 48000000;
fac_ms = (uint16_t)fac_us * 1000;
}
void delay_us(uint32_t nus)
{
unsigned int 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; //清空计数器
}
#if 1
void delay_ms(uint32_t nms)
{
unsigned int temp;
SysTick->LOAD= (uint32_t)nms * fac_ms; //时间加载(SysTick->LOAD为24bit)
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; //清空计数器
}
#else
void delay_ms(uint32_t nms)
{
uint32_t i = 0;
SysTick_Config(48000);
for(i = 0; i < nms; i++)
{
while(!((SysTick->CTRL) & ( 1<<16)));
}
SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk;
}
#endif
/******************************************/
uint32_t TimingDelay = 0;
void Delay_us(uint32_t nus)
{
SysTick_Config(SystemCoreClock/100000); //10us中断一次
TimingDelay = nus;
while(TimingDelay != 0);
}
void Delay_ms(uint32_t nms)
{
SysTick_Config(SystemCoreClock/1000); //1ms中断一次
TimingDelay = nms;
while(TimingDelay != 0);
}
usart.h
#ifndef USART_H_
#define USART_H_
#include "stm32f0xx.h"
#include <stdio.h>
void USART_Config(uint32_t BaudRate);
void USART1_Send_Char(unsigned char c);
void USART1_Send_String(char *s );
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);
void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num);
void Usart_SendString( USART_TypeDef * pUSARTx, char *str);
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch);
#endif /*USART_H_*/
usart.c
#include "usart.h"
#include "relay.h"
#include "delay.h"
uint8_t gRecvBuff[5];
uint8_t gRecvFlag = 0;
void USART_Config(uint32_t BaudRate)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//配置时钟
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_GPIOA , ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE );
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1); //Tx
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1); //Rx
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = BaudRate;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //接收一个字节中断
//USART_ITConfig(USART1,USART_IT_IDLE,ENABLE); //接收一帧数据中断
USART_Cmd(USART1, ENABLE);
}
uint8_t h = 0;
uint32_t gCount = 0;
void USART1_IRQHandler(void)
{
uint16_t temp = 0;
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//接收数据寄存器不为空
{
temp = USART_ReceiveData(USART1);
if((temp == 0xee) && (h == 0))
{
h = 1;
gRecvBuff[0] = temp;
}
else if( h == 1)
{
h = 2;
gRecvBuff[1] = temp;
}
else if(h == 2)
{
h = 3;
gRecvBuff[2] = temp;
}
else if(h == 3)
{
h = 4;
gRecvBuff[3] = temp;
}
else if(h == 4)
{
gRecvFlag = 1;
h = 0;
gRecvBuff[4] = temp;
gCount++; //记录有效指令条数
//printf("第%d条指令\n",gCount);
}
else
{
h = 0;
}
while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);
}
}
// 重定义
//int fputc(int ch, FILE *f)
//{
// while (!(USART1->ISR & USART_FLAG_TXE));
// USART1->TDR = ch;
//
// return (ch);
//}
///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到串口 */
USART_SendData(USART1, (uint8_t) ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return (ch);
}
int fgetc(FILE *f)
{
/* 等待串口输入数据 */
while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(USART1);
}
void USART1_Send_Char(unsigned char c)
{
while(!((USART1->ISR)&USART_FLAG_TXE));
USART1->TDR=c;
}
void USART1_Send_String(char *s )
{
while (*s)
USART1_Send_Char(*s++);
}
/***************** 发送一个字节 **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
/* 发送一个字节数据到USART */
USART_SendData(pUSARTx,ch);
/* 等待发送数据寄存器为空 */
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
/****************** 发送8位的数组 ************************/
void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
{
uint8_t i = 0;
for(i=0; i< num; i++)
{
/* 发送一个字节数据到USART */
Usart_SendByte(pUSARTx,array[i]);
}
/* 等待发送完成 */
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}
/***************** 发送字符串 **********************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
unsigned int k = 0;
do
{
Usart_SendByte( pUSARTx, *(str + k) );
k++;
} while(*(str + k)!='\0');
/* 等待发送完成 */
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
{}
}
/***************** 发送一个16位数 **********************/
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{
uint8_t temp_h, temp_l;
/* 取出高八位 */
temp_h = (ch&0XFF00)>>8;
/* 取出低八位 */
temp_l = ch&0XFF;
/* 发送高八位 */
USART_SendData(pUSARTx,temp_h);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
/* 发送低八位 */
USART_SendData(pUSARTx,temp_l);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
总结:
大体的功能基本具备,能够实现目标,但还存在一些问题,编写的代码并未完全利用,对于QT中的串口、定时器、各种进制之间的转换还需注意,串口发送及接收可以更好的处理;基于单片机的系统定时器(滴答定时器),硬件定时,通过串口传输数据等知识点需学习掌握。
遇到的问题:
-
能控制继电器但不能够正常工作,查看开发板的原理图时需注意继电器的工作电压,以及连接STM32核心板的引脚,便于控制继电器的工作;
-
未能够实现精确延时,需注意每个芯片的晶振频率;
-
需对传输的数据进行校验,在新指令到来时的处理需考虑清楚,容易出错;
-
对QT串口发送到单片机的数据是何种类型需了解;
-
获取程序异常状态信息,通过看门狗实现;
-
单片机能发送数据,上位机未能接收。