by HYH | 2017 年 9 月 13 日 下午 10:22
一.开发板简介
开发板上除了必须的晶振和复位电路,只有一个接在PB12上的led(用于测试)。
二.串口下载(stm32flash)
1.下载及安装。
官方下载:https://sourceforge.net/projects/stm32flash/files/(windows下载:stm32flash-0.5-win64.zip ,Linux下载:stm32flash-0.5.tar.gz)
下载地址:stm32flash-0.5.tar
32位 windows版下载地址:stm32flash-win32
解压之后,直接进入文件夹
make
make install
2.下载前的硬件设置.
1)除电源和地外,将USB转串口的RX接到PA9,TX接到PA10.
2)Boot0接高电平(正常运行时接低电平),Boot1接低电平。
3)连接完成后,按复位键。
3.常用命令(需root权限)
备份stm32的flash到文件:
stm32flash -r 备份文件名 串口设备名
从文件烧写stm32flash的flash:
stm32flash -w 文件名 串口设备名
4.附加:
由于rtthread的组件finsh组件,改变硬件连接(Boot0接低电平)并按复位键之后,可使用烧写串口调试(直接调用导出给finsh组件的C函数),无需更改串口连接。
调试波特率:115200
5.附加2:
在windows下,串口设备的表示方式为:COMn(n为整数,有时会失败)或 \\.\COMn(n为整数且兼容性更好)
其中n的值由通过设备管理器人工确定。
putty也可在windows下使用:
stm32flash在windows下使用时,需要将stm32flash.exe所在文件夹添加到PATH变量中,或者将stm32flash.exe放到PATH变量中有的目录(C:\windows)当中。运行stm32flash时最好使用管理员权限。如果打开串口失败,检查是否有其它软件(如putty)在使用该串口。
三.RT-thread编译以及简单使用。
1.编译环境搭建(arm-none-eabi-gcc+scons)
1)软件下载:
gcc:https://launchpad.net/gcc-arm-embedded/+download
python:https://www.python.org/downloads/
scons:http://scons.org/pages/download.html
可选软件:notepad++
2)安装注意事项:
gcc
安装过程中记好安装路径:
选择添加PATH变量
python
安装过程中记好安装路径:
选择添加PATH变量:
scons
必选先成功安装python.
安装完成后,手动将 python目录\scripts 添加到PATH变量。
如果能够运行scons即编译环境搭建完成:
2.rt-thread下载及编译前设置
1)下载
下载:http://www.rt-thread.org/page/31.html
http://pan.baidu.com/s/1mgIAyWo
将下载的zip包解压。
2)编译需要用到目录及文件简介(非开发)
examples\:rt-thread的示例。
bsp\:此目录下有rt-thread对各种芯片的支持,根据实际需要进入相应目录运行scons编译。如bsp\stm32f10x就是对stm32f103c6t8的支持,下面是对该目录的介绍:
rtconfig.py:编译工具设置,编译前必须设置好此文件。
rtconfig.h:rt-thread配置。通过注释取消注释来配置rt-thread。其中含有USING字样的为可选组件,可进行裁剪(组件间似乎有依赖关系,修改前最好备份)。
drivers:驱动文件夹,有的文件需要根据芯片实际情况或电路板外围电路情况进行修改。
applications:应用文件夹.其中startup.c为main函数所在文件。application.c包含一个led的任务,其调用的drivers\led.c中的函数控制一个led灯(用于显示正在运行)。
3)文件配置
rtconfig.py
CROSS_TOOL=’gcc’
EXEC_PATH = ‘gcc安装目录/bin‘(将路径中的\改为/)
drivers\board.h
#define STM32_SRAM_SIZE 实际内存大小
drivers\led.c
将led1改为PB12(所用开发板在PB12脚连了一个led)
#define led1_rcc RCC_APB2Periph_GPIOB
#define led1_gpio GPIOB
#define led1_pin (GPIO_Pin_12)
4)编译
scons 编译
scons -c 清理编译文件
5)烧录
rtthread.bin为烧录所用文件。
6)附加:
这样编译完成的rt-thread把唯一的一个led给占用了。为了释放这个led,可注释掉
rt_hw_led_init();
rt_hw_led_on(0);
rt_hw_led_off(0);
这样编译的固件,就不会占用led了。
就可使用drivers\led.c导出的led函数控制led了。(不存在led2,只有led1)。
led函数用法:
led(led选择,电平); led选择为1是选择led2,0选择led1.
7).附加2:
finsh简单使用:
list(); 查看已经导出的函数
list_thread(); 查看任务
list_timer();查看定时器
3.RT-thread简单开发
1)添加.c文件并使用FINSH打印字符
有时可能需要自己添加一个.c文件(以在applications\下添加一个app.c为例)。
首先新建一个名为app.c的文本文件。
编辑同目录的SConscript文件,将app.c添加到文件列的顶端。
接下来就是写app.c的内容
因为是用rt-thread开发应用,因此应当包含rtthread.h.
因为FINSH是可选组件,因此要在
#ifdef RT_USING_FINSH
#include <finsh.h>
和
#endif
之间写程序
然后就是写要导出的函数的主体了
其中rt_kprintf();可用于打印字符,用法跟printf()类似。
最后导出函数
FINSH_FUNCTION_EXPORT(函数名,描述)
注意:由于是宏定义,无须分号。
接下来就是编译
结果:
2)利用pin设备控制GPIO
要使用pin设备必须包含<drivers\pin.h>。
pin设备的引脚号数在stm32f10x下是由低层驱动(drivers\gpio.c)控制的.
如 __STM32_PIN(30, APB2, A, 5),表示30号引脚为PA5。
电平表示方式:
输入输出模式表示方式:
pin设备结构体:
pin输入输出模式结构体:
pin状态结构体:
常用函数:
rt_device_find(“pin”);//获取pin设备指针,返回值为rt_device_t,必须强制转换成rt_device_pin的指针.
rt_device_open(rt_device_pin的指针->parent,RT_NULL);//打开pin设备
rt_device_control(rt_device_pin的指针->parent,RT_NULL,pin输入输出模式结构体的指针);//应用输入输出模式
rt_device_write(rt_device_pin的指针->parent,RT_NULL,pin状态结构体的指针,sizeof(pin状态结构体));//写pin
rt_device_read(rt_device_pin的指针->parent,RT_NULL,pin状态结构体的指针,sizeof(pin状态结构体));//读pin
示例:
结果:
4.STM32F10X简单开发
rt-thread自带stm32f10x标准库,不依赖rt-thread.
目录:Libraries\STM32F10x_StdPeriph_Driver
1)GPIO口
GPIO口表示方式:GPIOA GPIOB … GPIOG (实际情况视芯片而定,对应的IO时钟为RCC_APB2Periph_GPIOA,RCC_APB2Periph_GPIOB … RCC_APB2Periph_GPIOG)
针脚表示方式:GPIO_PIN_n(n为数字)
如PA0的GPIO口为GPIOA,针脚为GPIO_PIN_0,IO时钟为RCC_APB2Periph_GPIOA。
要使用GPIO库函数,必须先包含stm32f10x_gpio.h
下面介绍几个常用的函数:
GPIO_ReadInputDataBit(GPIO口,针脚);
读取特定GPIO口的特定针脚。
GPIO_ReadInputData(GPIO口);
读取GPIO口
GPIO_ResetBits(GPIO口,针脚);
设置某个针脚为0
GPIO_SetBits(GPIO口,针脚);
设置某个针脚为1
下面是初始化示例代码:
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(IO时钟,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO模式;
GPIO_InitStructure.GPIO_Speed = GPIO速度;
GPIO_InitStructure.GPIO_Pin = 针脚;
GPIO_Init(GPIO口, &GPIO_InitStructure);
其中GPIO口,针脚,资源名可通过|号一次初始多个(如GPIO_PIN0|GPIO_PIN_1表示两个都初始化)
GPIO模式:
GPIO速度:
示例:
结果:
PA1接PA0(后三个命令)
用万用表测试PA1的电平变化也正确。
2)ADC示例(ADC1通道5)
代码:
#include <rtthread.h>
#include “stm32f10x_adc.h”
#ifdef RT_USING_FINSH
#include <finsh.h>
void ADC_Config(void) //ADC初始化
{
ADC_InitTypeDef ADC_1; //初始化结构体声明
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); //开启ADC1时钟,ADC2为RCC_APB2Periph_ADC1
ADC_StructInit(&ADC_1);//导入默认配置:独立模式,不扫描,不连续转换,TIM1_CC1事件触发,右对齐,通道数1
ADC_1.ADC_ScanConvMode = ENABLE;//开启扫描模式
ADC_1.ADC_ContinuousConvMode = ENABLE;//开启连续扫描模式
ADC_1.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//软件触发
ADC_Init(ADC1,&ADC_1); //初始化ADC1
ADC_RegularChannelConfig(ADC1,ADC_Channel_5,1,ADC_SampleTime_55Cycles5);//通道组,设置第五个通道的顺序为1,采样时间55.5周期
}
void GPIO_Config()//GPIO初始化,主要把ADC输入通道所在引脚配置为模拟输入模式
{
GPIO_InitTypeDef PA5;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIOA时钟
PA5.GPIO_Pin=GPIO_Pin_5;//第五引脚
PA5.GPIO_Mode=GPIO_Mode_AIN;//模拟输入模式
GPIO_Init(GPIOA,&PA5);//初始化PA5
}
void adctest()
{
uint16_t ad_v=0;//保存转换结果的变量
GPIO_Config();//调用GPIO初始化
ADC_Config();//调用ADC初始化
ADC_Cmd(ADC1,ENABLE);//开启ADC1
ADC_ResetCalibration(ADC1);//重置ADC1校准寄存器
while(ADC_GetResetCalibrationStatus(ADC1));//等待重置完成
ADC_StartCalibration(ADC1);//开始校准ADC1
while(ADC_GetCalibrationStatus(ADC1));//等待校准完成
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//开始软件触发
rt_kprintf(“start adc1(Channel_5)\n”);//调用finsh组件
while(1)
{
rt_thread_delay( RT_TICK_PER_SECOND/2 ); /* 睡眠0.5秒(RTthread功能) */
ad_v=ADC_GetConversionValue(ADC1);//获取最近的转换值
ad_v&=0x0fff;//保留右对齐的12位
rt_kprintf(“ADC1:%d\n”,ad_v);//调用finsh打印结果
}
}
FINSH_FUNCTION_EXPORT(adctest,test adc (pa5))
#endif
包含文件:stm32f10x_adc.h
通道号数由引脚第二功能决定(如PA5的第二功能是ADC_IN5,所以它是通道5)
示例结果:
3)UASRT(UART2查询方式)
#include <rtthread.h>
//#include <rtdevice.h>
//#include <drivers\serial.h>
#include <stm32f10x_usart.h>
#ifdef RT_USING_FINSH
#include <finsh.h>
void uartinit()//初始化GPIO,UART2
{
RCC_APB1PeriphClockCmd( RCC_APB1Periph_USART2, ENABLE);//打开UART2时钟
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA |RCC_APB2Periph_AFIO,ENABLE);//打开GPIOA(UART2所在GPIO口)时钟
GPIO_InitTypeDef GPIO_InitStructure;//GPIO初始化结构体
/*设置USART2 Tx(PA.2)*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*设置USART2 Rx(PA.3) */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure;//UASRT初始化结构体
USART_InitStructure.USART_BaudRate = 9600; //波特率9600
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//数据位8位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位1位
USART_InitStructure.USART_Parity = USART_Parity_No; //无校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//不开启流控制
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //收发模式
USART_Init(USART2, &USART_InitStructure);//初始化UASRT2
USART_Cmd(USART2, ENABLE); //启动UASRT2
}
void testuart()
{
uartinit();
while(1)
{
USART2->SR;//防止第一个字符被忽略
while (USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == RESET);//等待接收完成
USART_SendData(USART2, USART_ReceiveData(USART2));//发送接收的数据
while(USART_GetFlagStatus(USART2,USART_FLAG_TC)!=SET);//等待发送完成
}
}
FINSH_FUNCTION_EXPORT(testuart,uart2 test)
#endif
必须包含头文件:stm32f10x_usart.h
实验结果:
4)i2c(I2C1)
i2c的从硬件是PCF8591(8位AD/DA转换器)
#include <rtthread.h>
#include “stm32f10x_adc.h”
#ifdef RT_USING_FINSH
#include <finsh.h>
void i2c_init()//i2c初始化设置
{
I2C_InitTypeDef I2C_Struct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1 , ENABLE);
I2C_StructInit(&I2C_Struct);
I2C_Struct.I2C_ClockSpeed=100000;
I2C_Struct.I2C_Mode=I2C_Mode_I2C ;
I2C_Struct.I2C_DutyCycle=I2C_DutyCycle_2;
I2C_Struct.I2C_Ack=I2C_Ack_Enable; //使能应答位
I2C_Struct.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit ;
I2C_Init( I2C1, &I2C_Struct);
I2C_Cmd(I2C1,ENABLE);
}
void gpio_init()//设置i2c引脚
{
GPIO_InitTypeDef GPIO_Struct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOB,ENABLE);
GPIO_Struct.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;
GPIO_Struct.GPIO_Mode=GPIO_Mode_AF_OD;
GPIO_Struct.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_Struct);
}
void I2C_WaitEepromStandbyState(u8 id) //防守函数,非常重要
{
vu16 SR1_Tmp = 0;
do
{
/* Send START condition */
I2C_GenerateSTART(I2C1, ENABLE);
/* Read I2C1 SR1 register */
SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1);
/* Send EEPROM address for write */
I2C_Send7bitAddress(I2C1, id, I2C_Direction_Transmitter);
}while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002)); //estimate the value of ADDR
/* Clear AF flag */
I2C_ClearFlag(I2C1, I2C_FLAG_AF);
}
void i2c_write(u8 id,u8 address,u8 byte)//I2C写函数,参数依次是id,地址,要写入的值。(均是8位)
{
I2C_WaitEepromStandbyState(id);
I2C_GenerateSTART ( I2C1, ENABLE);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT)); //ev5
I2C_Send7bitAddress ( I2C1,id, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED )); //ev6
I2C_SendData ( I2C1, address);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTING)); //ev8
I2C_SendData ( I2C1, byte);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED)); //ev8_2
I2C_GenerateSTOP(I2C1, ENABLE);
}
u8 i2c_read(u8 id,u8 address)//i2c读函数,参数依次是id,地址。(均是8位)
{
u8 temp;
I2C_WaitEepromStandbyState(id);
I2C_GenerateSTART(I2C1, ENABLE);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));
I2C_AcknowledgeConfig(I2C1, DISABLE); //
I2C_Send7bitAddress ( I2C1,id, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData ( I2C1, address);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTING));
I2C_GenerateSTART(I2C1, ENABLE); //restart
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT)); //ev5
I2C_Send7bitAddress ( I2C1,id, I2C_Direction_Receiver);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); //ev6
I2C_GenerateSTOP(I2C1, ENABLE);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED)); //ev7
temp=I2C_ReceiveData(I2C1);
return temp;
}
int testi2c(void)
{
u8 data[5];//定义数组用于储存8位AD结果
gpio_init();
rt_kprintf(“GPIO init\n”);
i2c_init();
rt_kprintf(“start i2c\n”);
while(1)//读取pcf8591,A0=A1=A2=0
{
rt_thread_delay( RT_TICK_PER_SECOND/10 ); //睡眠0.1秒,读取过快可能引起死机.
data[0]=i2c_read(0x91,0x40);//读取通道0
data[1]=i2c_read(0x91,0x41);//读取通道1
data[2]=i2c_read(0x91,0x42);//读取通道2
data[3]=i2c_read(0x91,0x43);//读取通道3
data[4]=data[0];
i2c_write(0x90,0x40,data[4]);//DA转换
rt_kprintf(“\radc:%d %d %d %d\t\t”,data[0],data[1],data[2],data[3]);//打印AD结果
}
}
FINSH_FUNCTION_EXPORT(testi2c,test i2c)
#endif
必须包含的头文件:stm32f10x_adc.h
结果:
https://hyhsystem.cn/wordpress/
Copyright ?2018 何亚红的博客 unless otherwise noted.