文章目录

软件:keil5、STM32Cubemx
硬件:淘宝的STM32F103C8T6最小系统


选择外部时钟源。

设置外部晶振输入值,我这块板子是8M。
然后手动输入最大时钟频率,然后回车让他自动配置时钟树。我这块板子是72M。

我的下载器是SWD两根线的,所以我选这个。(一定配置完下载模式再进行程序下载,不然单片机变砖,需要从串口下载进行恢复)



点击生成代码

打开keil工程

选择下载器类型,我用的是DAP。点击后面的Setting。

进入后勾选自动复位,表现为每次下载程序后单片机自动复位运行程序。
设置完点击OK。

在工程目录下,新建一个ICODE文件夹,用于存放自己写的各种外设文件。

1 导入.c.h文件(就是将.c.h文件导入keil工程,后面不再叙述此环节)
将之前写好的 LED文件夹复制到本工程的ICODE目录下。
里边有led.c led.h文件夹。

在工程中,创建ICODE文件夹,添加led.c文件。

在工程中,添加led.h文件。


2 Cubemx配置
配置板子LED引脚,推挽输出模式。我这块板子是 PC13。
重新生成代码。

3 修改 .h 文件
更改为其他引脚,只需更改LED端口号和引脚PIN。我这块板子是PC13。

4 测试
在main.c中添加 #include “led.h”
在while里添加下面代码。LED灯闪烁。
LED_Contrary();
HAL_Delay(500);//500ms
1 导入.c.h文件(不再赘述,详细见LED部分)
无
2 Cubemx配置
和PC13冲突,核心板PC13是LED,所以禁用RTC OUT。

3 修改 .c 文件
在中断.c里,填加led头文件,在RTC中断函数里,加入500ms,LED电平反转函数。
#include "led.h"
static uint16_t rtccnt=0;
rtccnt++;
if(rtccnt>500) rtccnt=0,LED_Contrary();

4 测试
LED闪烁。
1 导入.c.h文件(不再赘述,详细见LED部分)
在keil工程中导入之前写好的.c.h文件。

勾选使用

2 Cubemx配置
使用串口1,波特率默认,异步通信。

开启中断

3 修改 .h 文件
代码默认使用串口1。添加其他串口可以在.h里,复制,改名。

4 测试
串口发送/接收函数:
HAL_UART_Transmit();串口发送数据,使用超时管理机制
HAL_UART_Receive();串口接收数据,使用超时管理机制
HAL_UART_Transmit_IT();串口中断模式发送
HAL_UART_Receive_IT();串口中断模式接收
HAL_UART_Transmit_DMA();串口DMA模式发送
HAL_UART_Transmit_DMA();串口DMA模式接收
串口中断函数:
HAL_UART_IRQHandler(UART_HandleTypeDef *huart); //串口中断处理函数
HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart); //串口发送中断回调函数
HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart); //串口发送一半中断回调函数(用的较少)
HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); //串口接收中断回调函数
HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);//串口接收一半回调函数(用的较少)
HAL_UART_ErrorCallback();串口接收错误函数
常用的发送函数为:HAL_UART_Transmit();
常用的接收函数为:HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
HAL库串口中断调用流程:

发送:
1 printf重映射:
/* printf重映射 */
#include <stdio.h>
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
//具体哪个串口可以更改huart1为其它串口
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1 , 0xffff);
return ch;
}
2 printf发送:
printf("hello \r\n"); //发送字符串
float Data=1.11;
printf("Data=%.2f \r\n",Data); //发送变量
3 Hal库自带发送函数:
#include <stdio.h>
HAL_UART_Transmit(&huart1,"hello\r\n",sizeof("hello\r\n"),0xffff);//发送字符串
uint8_t Data1[]={"hello\r\n"};
HAL_UART_Transmit(&huart1,Data1,sizeof(Data1),0xffff);//发送字符串
uint8_t Databuffer[20]={0};
float Data=1.11;
sprintf(Databuffer,"Data=%.2f \r\n",Data);
HAL_UART_Transmit(&huart1,Databuffer,strlen(Databuffer),0xffff);//发送变量 用strlen
中断接收:
1 定长
/*
串口接收中断
定长接收
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart1)
{
HAL_UART_Transmit(&huart1,(uint8_t *)&Uart1_RxData,1,0xffff);//原样返回
while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX);//检测UART发送结束
HAL_UART_Receive_IT(&huart1,(uint8_t *)&Uart1_RxData, 1); //&取地址
}
}
2 不定长
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
if(huart == &huart1)
{
if(Uart1_Rx_Cnt >= 255) //溢出判断
{
Uart1_Rx_Cnt = 0;
memset(Uart1_RxBuffer,0x00,sizeof(Uart1_RxBuffer));
HAL_UART_Transmit(&huart1, (uint8_t *)"数据溢出", 10,0xFFFF);
}
else
{
Uart1_RxBuffer[Uart1_Rx_Cnt++] = Uart1_RxData; //接收数据转存
if((Uart1_RxBuffer[Uart1_Rx_Cnt-1] == 0x0A)&&(Uart1_RxBuffer[Uart1_Rx_Cnt-2] == 0x0D)) //判断结束位\r\n。0x0D是\r,0x0A是\n
{
/* 此处添加用户代码 */
HAL_UART_Transmit(&huart1, (uint8_t *)&Uart1_RxBuffer, Uart1_Rx_Cnt,0xFFFF); //将收到的信息发送出去
while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX);//检测UART发送结束
/* 此处添加用户代码 */
Uart1_Rx_Cnt = 0;
memset(Uart1_RxBuffer,0x00,sizeof(Uart1_RxBuffer)); //清空数组
}
}
HAL_UART_Receive_IT(&huart1, (uint8_t *)&Uart1_RxData, 1); //再开启接收中断
}
}
1 导入.c.h文件(不再赘述,详细见LED部分)
在keil工程中导入之前写好的.c.h文件。
2 Cubemx配置
3 修改 .h 文件
4 测试
1 导入.c.h文件(不再赘述,详细见LED部分)
在keil工程中导入之前写好的.c.h文件。选择IIC的或者SPI的。(模拟IIC和模拟SPI)


2 Cubemx配置
任选对应OLED引脚个数的GPIO,设置成推挽输出。设置为高速。

3 修改 .h 文件
更改为其他引脚,只需更改OLED端口号和引脚PIN

4 测试
OLED 显示字体大小 16*16 最合适。能放4行:0 16 32 48。
添加头文件
#include "oled.h"
添加初始化
OLED_Init();
OLED_ColorTurn(0); //0正常显示,1 反色显示
OLED_DisplayTurn(0); //0正常显示 1 屏幕翻转显示
1 显示字符:
OLED_ShowString(0,0,"hello",16,1);
OLED_Refresh();//更新0
2 显示变量:
uint8_t Databuffer[20]={0};
float Data=1.11;
sprintf(Databuffer,"Data=%.2f \r\n",Data);//sprintf
OLED_ShowString(0,16,Databuffer,16,1);
OLED_Refresh();
3 显示中文:

1 导入.c.h文件(不再赘述,详细见LED部分)
在keil工程中导入之前写好的.c.h文件。
2 Cubemx配置
3 修改 .h 文件
4 测试
添加头文件
添加初始化
1 导入.c.h文件(不再赘述,详细见LED部分)
在keil工程中导入之前写好的.c.h文件。

2 Cubemx配置
随意选一个ADC引脚。初始化ADC引脚。
3 修改 .h 文件
4 测试
添加头文件
#include "mq2.h"
采集
uint16_t MQ2_DATA=0;
MQ2_DATA = GetMQ4Value();
同MQ2,AD读取。
浓度转化函数:
uint16_t GetMQ4Value(void)
{
uint16_t ADCVal;
float Voltage;
uint16_t ppm;
HAL_ADC_Start(&hadc1);//开始ADC采集
HAL_ADC_PollForConversion(&hadc1,500);//等待采集结束
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))//读取ADC完成标志位
{
ADCVal = HAL_ADC_GetValue(&hadc1);//读出ADC数值
}
Voltage = ADCVal * 3.3 / 4096;
//无天然气的环境下,实测AOUT端的电压为0.5V,当检测到天然气时,电压每升高0.1V,实际被测气体浓度增加200ppm
ppm = (Voltage - 0.5) / 0.1 * 200;
return ppm;
//return ADCVal;
}
1 导入.c.h文件(不再赘述,详细见LED部分)
在keil工程中导入之前写好的.c.h文件。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4kFUCvSv-1681004471418)(null)]
2 Cubemx配置
任选一个IO口,配置为高速,推挽输出。
1 导入.c.h文件(不再赘述,详细见LED部分)
在keil工程中导入之前写好的.c.h文件。

2 Cubemx配置
随意选择一个IO口。配置为推挽输出,高速。
3 修改 .h 文件
定义DHT11总线连接的GPIO端口, 只需要修改下面2行代码即可任意改变DATA的引脚

4 测试
添加头文件
#include "dht11.h"
添加初始化
DHT11_Init(); //DHT11温湿模块初始化
读取温湿度
uint8_t DHT11_DATA[2]={0}; //用于存放DHT11温湿度数据
DHT11_ReadData(DHT11_BUF); //读出DHT11传感器数据(参数是存放数据的数组指针)
printf("湿度:%2d% 温度:%2d℃\r\n",DHT11_BUF[0],DHT11_BUF[1]);//串口打印湿度温度
1 导入.c.h文件(不再赘述,详细见LED部分)
在keil工程中导入之前写好的.c.h文件。
2 Cubemx配置
3 修改 .h 文件
4 测试
添加头文件
添加初始化
1 导入.c.h文件(不再赘述,详细见LED部分)
在keil工程中导入之前写好的.c.h文件。

2 Cubemx配置
采用模拟IIC,任意选两个io口设置为推挽输出模式。我这边选B7 B6。
配置串口1,重映射printf。
cubemx基本工程和配置看:【HAL库】HAL库STM32cubemx快速使用
3 修改 .h 文件
只需要修改下面2行代码即可任意改变引脚

4 测试
添加头文件
#include "bmp1801.h"
添加初始化
BMP_Init(); //BMP180初始化
BMP_ReadCalibrationData();//BMP180初始化
读取
uint8_t ID = 0; //BMP180器件号
ID = BMP_ReadOneByte(0xd0); //读取设备ID
BMP_UncompemstatedToTrue(); //读取气压值
printf("ID = %d\t temp = %d.%dC\t Pressure = %.2fkPa\t Altitude = %.5fm\r\n",ID,bmp180.Temp/10,bmp180.Temp%10,(float)bmp180.p/1000.0,bmp180.altitude);
HAL_Delay(500);

1 导入.c.h文件(不再赘述,详细见LED部分)
在keil工程中导入之前写好的.c.h文件。
2 Cubemx配置
3 修改 .h 文件
4 测试
添加头文件
添加初始化
1 导入.c.h文件(不再赘述,详细见LED部分)
在keil工程中导入之前写好的.c.h文件。

2 Cubemx配置
串口1用于调试,串口3用于ESP8266通信,打开中断。
基础的我就不配置了,可以看前面的详细讲解。
3 修改 .c.h 文件
移植时要修改的地方:
1 改所用串口
发送部分:在esp8266.c里,将huart3全部替换为要修改的串口号,比如串口2。

接收部分:用串口中断接收esp8266发来的消息。随便在哪个文件夹填加串口回调函数,我个人是之前专门建了个uart.c文件放串口相关的所有代码。
加入下面的代码(串口号根据个人情况修改)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart3)//esp8266接收云平台数据
{
if(esp8266_cnt >= sizeof(esp8266_buf))
{
esp8266_cnt = 0; //防止串口被刷爆
}
esp8266_buf[esp8266_cnt++] = Uart3_RxData;
HAL_UART_Receive_IT(&huart3,(uint8_t *)&Uart3_RxData, 1); //&取地址
}
}
2 改wifi名字和密码

3 改产品ID、设备ID、鉴权信息。

4 测试
添加头文件
#include "onenet.h"
#include "esp8266.h"
添加初始化
别忘了开串口中断。
HAL_UART_Receive_IT(&huart3,(uint8_t *)&Uart3_RxData, 1);//开启串口中断
/* esp8266连接wifi+连接Onenet */
HAL_Delay(2000);
ESP8266_Init(); //初始化ESP8266,连接wifi
HAL_Delay(2000);
while(OneNet_DevLink()) //连接OneNET
HAL_Delay(2000);
连接成功的话,onenet会显示设备在线。串口也会打印成功。


发送数据
OneNet_SendData(); //发送数据
ESP8266_Clear(); //清空数据缓存区
HAL_Delay(3000); //3s发送一次

要发什么数据,在这里改:

接收数据
dataPtr = ESP8266_GetIPD(0);//获取平台返回的数据
if(dataPtr != NULL)//如果返回数据不为空
OneNet_RevPro(dataPtr);//平台返回数据检测
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po