单片机的一些总结
- 按键没有按下的时候是高电平,按下时低电平。(接地)
- 当型循环,输入空语句可以停止整个主程序的循环。
STM32小说明
1、数据手册标注FT的IO口,都是兼容5V。有ADC都不兼容5V。
2、重映射?F103有效,F4无重映射概念。
3、ADC/PI/PWM
原理图
- 波特率一般用于描述串口通讯的速度、速率的指标,指串口每秒能传输多少位数据
所谓波特率是比特每秒的翻译,就是位每秒的传输速度单位
比如波特率为9600,即传输速度是9600bit/s,等于1200字节每秒的传输速度,那么19200bit/s=2400字节每秒,比9600bit/s快一倍。
跳线帽的作用是控制线路板上电流流动的小开关。
1 主板跳线是主机板上的手动开关,通过跳线帽连接不同的跳线PIN,可以改变主板电路;
2 主板上最常见的跳线主要有两种,一种是只有两根针,另一部分是跳线帽;
3 跳线帽,这是一个可以活动的部件,外层是绝缘塑料,内层是导电材料,可以插在跳线针上面,将两根跳线针连接起来;
4 当跳线帽扣在两根跳线针上时是接通状态,有电流通过,我们称之为ON;
5 反之不扣上跳线帽时,就说明是断开的,称之为OFF。
6、tx是发送(transport),rx是接收(receive)。
7、user文件夹 用来存放main函数、启动文件 OBJ主要用来生成过程文件,hex文件(flymcu直接搞定,不需要烧录器)
8、
9、USART
USART:(Universal Synchronous/Asynchronous Receiver/Transmitter)
通用同步/异步串行接收/发送器
USART是一个全双工通用同步/异步串行收发模块,该接口是一个高度灵活的串行通信设备。
中文名
USART
外文名
Universal Synchronous/Asynchronous Receiver/Transmitter
主要特点
支持同步和异步操作
结构组成
时钟发生器、数据发送器和接收器
三大部分
时钟发生器、数据发送器和接收器
- Asynchronous
同步和异步通常用来形容一次方法调用。
同步方法调用一旦开始,调用者必须等到方法调用返回后,才能继续后续的行为。
异步方法调用更像一个消息传递,一旦开始,方法调用就会立即返回,调用者就可以继续后续的操作。而,异步方法通常会在另外一个线程中,“真实”地执行着。整个过程,不会阻碍调用者的工作。
12.
CMSIS是ARM公司与多家不同的芯片和软件供应商一起紧密合作定义的,提供了内核与外设、实时操作系统和中间设备之间的通用接口。
13、gpio
General Purpose Input Output (通用输入/输出)简称为GPIO,或总线扩展器,人们利用工业标准I2C、SMBus或SPI接口简化了I/O口的扩展。当微控制器或芯片组没有足够的I/O端口,或当系统需要采用远端串行通信或控制时,GPIO产品能够提供额外的控制和监视功能。
还可以复用为外设功能引脚:如看门狗、定时器
14、
https://baike.baidu.com/item/%E5%BC%95%E8%84%9A/10879873?fr=aladdin
引脚
引脚,又叫管脚,英文叫Pin。就是从集成电路(芯片)内部电路引出与外围电路的接线,所有的引脚就构成了这块芯片的接口。引线末端的一段,通过软钎焊使这一段与印制板上的焊盘共同形成焊点。引脚可划分为脚跟(bottom)、脚趾(toe)、脚侧(side)等部分。
15、
串行接口
同义词 串口一般指串行接口
串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口。串行接口(Serial Interface) 是指数据一位一位地顺序传送,其特点是通信线路简单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成本,特别适用于远距离通信,但传送速度较慢。
- 比特率
https://baike.baidu.com/item/BPS/607603?fr=aladdin
bps(bits per second),即比特率、比特/秒、位/秒、每秒传送位数,数据传输速率的常用单位。详见Mbps。
比特(bit)是信息技术中的最小单位。文件大小(例如文本或图像文件)通常以字节(Byte)为单位。一字节对应八比特。在数据传输中,数据通常是串行传输的,即一个比特接一个比特地传输。数据速率的单位是比特每秒(bps),含义是每秒串行通过的位数。
Bps (Bytes per second), 即字节每秒,因为一字节对应八比特,所以1 Bps = 8bps。
- GPIO四种输入模式
输入浮空、上拉、下拉、模拟输入
18、
https://baike.baidu.com/item/Cortex-M3/5614686
Cortex-M3是一个32位处理器内核。内部的数据路径是32位的,寄存器是32位的,存储器接口也是32位的。CM3采用了哈佛结构,拥有独立的指令总线和数据总线,可以让取指与数据访问并行不悖。这样一来数据访问不再占用指令总线,从而提升了性能。为实现这个特性,CM3内部含有好几条总线接口,每条都为自己的应用场合优化过,并且它们可以并行工作。但是另一方面,指令总线和数据总线共享同一个存储器空间(一个统一的存储器系统)。换句话说,不是因为有两条总线,可寻址空间就变成8GB了。
19、
https://baike.baidu.com/item/Cortex-M4/7085070?fr=aladdin
ARMCortex™-M4处理器是由ARM专门开发的最新嵌入式处理器,在M3的基础上强化了运算能力,新加了浮点、DSP、并行计算等,用以满足需要有效且易于使用的控制和信号处理功能混合的数字信号控制市场。其高效的信号处理功能与Cortex-M处理器系列的低功耗、低成本和易于使用的优点的组合,旨在满足专门面向电动机控制、汽车、电源管理、嵌入式音频和工业自动化市场的新兴类别的灵活解决方案。
20、
ARM
(英国ARM公司)
英国ARM公司是全球领先的半导体知识产权 (IP) 提供商。全世界超过95%的智能手机和平板电脑都采用ARM架构[1] 。ARM设计了大量高性价比、耗能低的RISC处理器、相关技术及软件。2014年基于ARM技术的全年全球出货量是120亿颗,从诞生到现在为止基于ARM技术的芯片有600亿颗[2] 。技术具有性能高、成本低和能耗省的特点。在智能机、平板电脑、嵌入控制、多媒体数字等处理器领域拥有主导地位。
AD转换
AD转换就是模数转换。顾名思义,就是把模拟信号转换成数字信号。主要包括积分型、逐次逼近型、并行比较型/串并行型、Σ-Δ调制型、电容阵列逐次比较型及压频变换型。
A/D转换器是用来通过一定的电路将模拟量转变为数字量。模拟量可以是电压、电流等电信号,也可以是压力、温度、湿度、位移、声音等非电信号。但在A/D转换前,输入到A/D转换器的输入信号必须经各种传感器把各种物理量转换成电压信号。
23、
施密特触发器
24、
红色贴片LED 电压1.6V至2.4V
万用表
限流电阻
25.
Flash 程序储存空间 断电 程序仍存在rom 擦写十万次
Ram 内存 无限次擦写 读取速度特别快 存储变量 和一些中间计算的值
26.
大写P1 P0
ARDUINO
1输入输出函数
Arduino 内含了一些处理输出与输入的切换功能,相信已经从书中程式范例略知一二。
pinMode(pin, mode)
将数位脚位(digital pin)指定为输入或输出。
范例 :
pinMode(7,INPUT); // 将脚位 7 设定为输入模式
digitalWrite(pin, value)
将数位脚位指定为开或关。脚位必须先透过pinMode明示为输入或输出模式digitalWrite才能生效。
范例 :
digitalWrite(8,HIGH); //将脚位 8设定输出高电位
int digitalRead(pin)
将输入脚位的值读出,当感测到脚位处于高电位时时回传HIGH,否则回传LOW。
范例 :
val = digitalRead(7); // 读出脚位 7 的值并指定给 val
int analogRead(pin)
读出类比脚位的电压并回传一个 0到1023 的数值表示相对应的0到5的电压值。
范例 :
val = analogRead(0); //读出类比脚位 0 的值并指定给 val变数
analogWrite(pin, value)
改变PWM脚位的输出电压值,脚位通常会在3、5、6、9、10与11。Value变数范围0-255,例如:输出电压2.5伏特(V),该值大约是128。
范例 :
analogWrite(9,128); // 输出电压约2.5伏特(V)
unsigned long pulseIn(pin, value)
设定读取脚位状态的持续时间,例如使用红外线、加速度感测器测得某一项数值时,在时间单位内不会改变状态。
范例 :
time = pulsein(7,HIGH); // 设定脚位7的状态在时间单位内保持为HIGH
shiftOut(dataPin, clockPin, bitOrder, value)
把资料传给用来延伸数位输出的暂存器,函式使用一个脚位表示资料、一个脚位表示时脉。bitOrder用来表示位元间移动的方式(LSBFIRST最低有效位元或是MSBFIRST最高有效位元),最后value会以byte形式输出。此函式通常使用在延伸数位的输出。
范例 :
shiftOut(dataPin, clockPin, LSBFIRST, 255);
时间函数
控制与计算晶片执行期间的时间
unsigned long millis()
回传晶片开始执行到目前的毫秒
范例:
duration = millis()-lastTime; // 表示自"lastTime"至当下的时间
delay(ms)
暂停晶片执行多少毫秒
范例:
delay(500); //暂停半秒(500毫秒)
delay Microseconds(us)
暂停晶片执行多少微秒
范例:
delayMicroseconds(1000); //暂停1豪秒
数学函式
三角函数以及基本的数学运算
min(x, y)
回传两数之间较小者
范例:
val = min(10,20); // 回传10
max(x, y)
回传两数之间较大者
范例:
val = max(10,20); // 回传20
abs(x)
回传该数的绝对值,可以将负数转正数。
范例:
val = abs(-5); // 回传5
constrain(x, a, b)
判断x变数位于a与b之间的状态。x若小于a回传a;介于a与b之间回传x本身;大于b回传b
范例:
val = constrain(analogRead(0), 0, 255); // 忽略大于255的数
map(value, fromLow, fromHigh, toLow, toHigh)
将value变数依照fromLow与fromHigh范围,对等转换至toLow与toHigh范围。时常使用于读取类比讯号,转换至程式所需要的范围值。
例如:
val = map(analogRead(0),0,1023,100, 200); // 将analog0 所读取到的讯号对等转换至100 – 200之间的数值。
double pow(base, exponent)
回传一个数(base)的指数(exponent)值。
范例:
double x = pow(y, 32); // 设定x为y的32次方
double sqrt(x)
回传double型态的取平方根值。
范例:
double a = sqrt(1138); // 回传1138平方根的近似值 33.73425674438
double sin(rad)
回传角度(radians)的三角函数sine值。
范例:
double sine = sin(2); // 近似值 0.90929737091
double cos(rad)
回传角度(radians)的三角函数cosine值。
范例:
double cosine = cos(2); //近似值-0.41614685058
double tan(rad)
回传角度(radians)的三角函数tangent值。
范例:
double tangent = tan(2); //近似值-2.18503975868
乱数函式
产生乱数
randomSeed(seed)
事实上在Arduino里的乱数是可以被预知的。所以如果需要一个真正的乱数,可以呼叫此函式重新设定产生乱数种子。你可以使用乱数当作乱数的种子,以确保数字以随机的方式出现,通常会使用类比输入当作乱数种子,藉此可以产生与环境有关的乱数(例如:无线电波、宇宙雷射线、电话和萤光灯发出的电磁波等)。
范例:
randomSeed(analogRead(5)); // 使用类比输入当作乱数种子
long random(max)
long random(min, max)
回传指定区间的乱数,型态为long。如果没有指定最小值,预设为0。
范例:
long randnum = random(0, 100); // 回传0 – 99 之间的数字
long randnum = random(11); // 回传 0 -10之间的数字
序列通讯
你可以在第五章看见一些使用序列埠与电脑交换讯息的范例,以下是函式解释。
Serial.begin(speed)
你可以指定Arduino从电脑交换讯息的速率,通常我们使用9600 bps。当然也可以使用其他的速度,但是通常不会超过115,200 bps(每秒位元组)。
范例:
Serial.begin(9600);
Serial.print(data)
Serial.print(data, encoding)
经序列埠传送资料,提供编码方式的选项。如果没有指定,预设以一般文字传送。
范例:
Serial.print(75); // 列印出 "75"
Serial.print(75, DEC); //列印出 "75"
Serial.print(75, HEX); // "4B" (75 的十六进位)
Serial.print(75, OCT); // "113" (75 in的八进位)
Serial.print(75, BIN); // "1001011" (75的二进位)
Serial.print(75, BYTE); // "K" (以byte进行传送,显示以ASCII编码方式)
Serial.println(data)
Serial.println(data, encoding)
与Serial.print()相同,但会在资料尾端加上换行字元( )。意思如同你在键盘上打了一些资料后按下Enter。
范例:
Serial.println(75); //列印出"75 "
Serial.println(75, DEC); //列印出"75 "
Serial.println(75, HEX); // "4B "
Serial.println(75, OCT); // "113 "
Serial.println(75, BIN); // "1001011 "
Serial.println(75, BYTE); // "K "
int Serial.available()
回传有多少位元组(bytes)的资料尚未被read()函式读取,如果回传值是0代表所有序列埠上资料都已经被read()函式读取。
范例:
int count = Serial.available();
int Serial.read()
读取1byte的序列资料
范例:
int data = Serial.read();
Serial.flush()
有时候因为资料速度太快,超过程式处理资料的速度,你可以使用此函式清除缓冲区内的资料。经过此函式可以确保缓冲区(buffer)内的资料都是最新的。
范例:
Serial.flush();
2--analogWrite():
功能:给端口写入一个模拟值(PWM波)。
可以用来控制LED灯的亮度变化,或者以不同的速度驱动马达。
当执行analogWrite()命令后,端口会输出一个稳定的占空比的方波。除非有下一个命令来改变它。
PWM信号的频率大约为490Hz.
在使用analogWrite()命令前,可以不使用pinMode()命令把端口定义为输出端口,当然如果定义了更好,这样利于程序语言规范。
#if 条件 1
代码段 1
#elif 条件 2
代码段 2
...
#elif 条件 n
代码段 n
#else
代码段 n+1
#endif
2、#ifdef, #else, #endif或#ifndef, #else, #endif
参数为宏名(无需加""),如果该macro_name定义过则返回真,否则返回假,用该函数则可以写比较复杂的条件编译指令如
#if defined(macro1) || (!defined(macro2) && defined(macro3))
...
#else
...
#endif
首先比较一下这两种方法,第一种方法只能判断一个宏,如果条件比较复杂实现起来比较烦锁,用后者就比较方便。如有两个宏MACRO_1,MACRO_2只有两个宏都定义过才会编译代码段A,分别实现如下:
#ifdef MACRO_1
#ifdef MACRO_2
代码段 A
#endif
#endif
或者
#if defined(MACRO_1) && defined(MACRO_2)
#endif
比如自己写了一个printf函数,想通过一个宏MY_PRINTF_EN实现条件编译,用#if可实现如下
#define MY_PRINTF_EN 1
#if MYS_PRINTF_EN == 1
int printf(char* fmt, char* args, ...)
{
...
}
#endif
如果宏MY_PRINTF_EN定义为1则编译这段代码,如果宏定义不为1或者没有定义该宏,则不编译这段代码。同样也可以通过#ifdef或者#defined()实现,如
在这种情况下两种方法具有异曲同工之妙,但试想如果你为了节约代码写了两个printf函数,在不同情况下使用不同的printf函数,一个是精简版一个是全功能标准版,如:
两种方法都可以实现,但可见后者更方便。但试想如果你有三个版本,用前者就更麻烦了,但方法相似,用后者就更方便,但仍需三个宏进行控制,你要住三个宏,改进一下就用#if可以用一个宏直接控制N种情况如:
看来好像用#if 比较好了,试想如下情况:你写了一个配置文件叫做config.h用来配置一些宏,通过这些宏来控制代码,如你在config.h的宏
来控制是否需要编译自己的printf函数,而在你的源代码文件printf.c中有如下指令
#i nclude "config.h"
#if MY_PRINTF_EN == 1
int printf(char* fmt, char* args, ...)
{
...
}
#endif
再试想,如果软件升级了,或者有了大的改动,原来有三个版本,现在只剩下两个版本了,如
因为这些核心代码不想让使用这些代码的人关心,他们只需要修改config.h文件,那就要在printf.c中实现兼容性。如果以前有人在config.h配置宏MY_PRINTF_VERSION为1,即有
而现在没有1版本了,要想兼容怎么办?那当然可以用更复杂的条件实现如:
道德static 赋值语句只有一个有效,而且只能在本函数中使用(赋值,判断),
void turnL(int m) //左转
{
motor(4,5,1,m);
motor(7,6,0,m);
}
void motor(char pin,char pwmpin,char state,int val)
{
pinMode(pin, OUTPUT);
if(state==1)
{
analogWrite(pwmpin,val);
digitalWrite(pin,1);
}
else if(state==2)
{
analogWrite(pwmpin,val);
digitalWrite(pin,0);
}
else if(state==0)
{
analogWrite(pwmpin,0);
digitalWrite(pin,0);
}
}
按键函数
u8 KEY_Scan(u8 mode)
{
static u8 key_up=1;
if(mode)key_up=1;
if(key_up&&(KEY0==0||KEY1==0||KEY2==0||WK_UP==1))
{
delay_ms(10);
key_up=0;
if(KEY0==0)return 1;
else if(KEY1==0)return 2;
else if(KEY2==0)return 3;
else if(WK_UP==1)return 4;
}else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0)key_up=1;
return 0;
}
- 如果都是返回同一个值,一个是隐条件语句,一个是明条件,明条件语句写在最后。
- 先写最复杂情况条件的语句,再去想从里面分离出简单情况,简单情况就是复杂情况的某些变量为一个定值。
- 追根溯源,flag要为常量,那为什么会改变呢?——赋值语句改变——那么再用赋值语句变回来不相当于常量了吗?——或者根据条件判断之后,再进行赋值语句,就相当于判断模式之后,再决定它是常量还是变量。
比较大小函数的新奇写法
for (int i = 0; i <w; i++)
{
int j = 0;//重新开始,从头比较
for (; j<w; j++)
{
if (p[i]->S() > p[j]->S())break;
}
if (j == w)
{
cout <<"面积最小的图形的面积为:"<< p[i]->S() << endl << "面积最小的图形的周长为:"<<p[i]->C() << endl;
}
}
一个符号的意义:
P1SEL &= ~0x3
0x3=0011 &=~就是把有1的位全被清零,有0的位全部不变,比如,这个例子,P1SEL的最后两位清零,其余不变。
\r回到该句子的首端
\n到达下一个句子的首端
串口标志位
http://www.openedv.com/posts/list/0/58919.htm
TXE是指“弹仓”空;
TC是“枪膛”空。
这个形象。
也就是说,你写数据到串口时,是装入弹仓,硬件会将数据移到枪膛,这时,TXE为1,TC为0,STM32硬件的TX脚正在发送数据,但你还可以装入数据到弹仓,装入后,TXE为0,TC为0.
TX发送完一个数据后,立即将数据从弹仓移入枪膛,这时,TXE为1,TC为0.
最后TX发送完数据,你又没有装入新数据,这时。TXE为1,TC为1.
USART里面TXE和TC的用法
http://blog.****.net/u014170207/article/details/48225189
STM32库函数void USART_SendData的缺陷和解决方法
修改前的函数定义体
void USART_SendData(USART_TypeDef* USARTx, u16 Data)
{
assert_param(IS_USART_ALL_PERIPH(USARTx));
assert_param(IS_USART_DATA(Data));
USARTx->DR = (Data & (u16)0x01FF);
}
修改后的函数定义体
void USART_SendData(USART_TypeDef* USARTx, u16 Data)
{
assert_param(IS_USART_ALL_PERIPH(USARTx));
assert_param(IS_USART_DATA(Data));
USARTx->DR = (Data & (u16)0x01FF);
while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET){} //等待发送缓冲区空才能发送下一个字符
}
方案3. 不修改原来的库函数,在每一个字符发送后检测状态位。
USART_SendData(USART1, RxBuffer[TxCounter]);
while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET){} //等待发送缓冲区空才能发送下一个字符
使用USART_SendData()函数非连续发送单个字符是没有问题的;当连续发送字符时(两个字符间没有延时),就会发现发送缓冲区有溢出现象。若发送的数据量很小时,此时串口发送的只是最后一个字符,当发送数据量大时,就会导致发送的数据莫名其妙的丢失。
http://blog.****.net/qq_27114397/article/details/50601548
GPIO 功能描述
根据数据手册中列出的每个 I/O 端口的特性,可通过软件将通用 I/O (GPIO) 端口的各个端口
位分别配置为多种模式:
● 输入浮空
● 输入上拉
● 输入下拉
● 模拟功能
● 具有上拉或下拉功能的开漏输出
● 具有上拉或下拉功能的推挽输出
● 具有上拉或下拉功能的复用功能推挽
● 具有上拉或下拉功能的复用功能开漏
调试
单步调试时,调试窗口显示寄存器的数值时已经读过了DR寄存
所以你再次单步时就看到标志已经被清除。
|
|
STM32F1与F4的差别
STM32F4相对于STM32F1的改进不只一点点,为了便于初学者了解,我们比对相关资料将改进点进行了汇总。
STM32F1和STM32F4 区别 (安富莱整理)
F1采用Crotex M3内核,F4采用Crotex M4内核。
F1最高主频 72MHz, F4最高主频168MHz。
F4具有单精度浮点运算单元,F1没有浮点运算单元。
F4的具备增强的DSP指令集。F4的执行16位DSP指令的时间只有F1的30%~70%。F4执行32位DSP指令 的时间只有F1的25%~60%。
F1内部SRAM最大64K字节, F4内部SRAM有192K字节(112K+64K+16K)。
F4有备份域SRAM(通过Vbat供电保持数据),F1没有备份域SRAM。
F4从内部SRAM和外部FSMC存储器执行程序的速度比F1快很多。F1的指令总线I-Bus只接到Flash上,从SRAM和FSMC取指令只能通过S-Bus,速度较慢。F4的I-Bus不但连接到Flash上,而且还连接到SRAM和FSMC上,从而加快从SRAM或FSMC取指令的速度。
F1最大封装为144脚,可提供112个GPIO;F4最大封装有176脚,可提供140个GPIO。
F1的GPIO的内部上下拉电阻配置仅仅针对输入模式有用,输出时无效。而F4的GPIO在设置为输出模式时,上下拉电阻的配置依然有效。即F4可以配置为开漏输出,内部上拉电阻使能,而F1不行。
F4的GPIO最高翻转速度为84MHz,F1最大翻转速度只有18MHz。
F1最多可提供5个UART串口,F4最多可以提供6个UART串口。
F1可提供2个I2C接口,F4可以提供3个I2C接口。
F1和F4都具有3个12位的独立ADC,F1可提供21个输入通道,F4可以提供24个输入通道。F1的ADC最大采样频率为1Msps,2路交替采样可到2Msps(F1不支持3路交替采样)。F4的ADC最大采样频率为2.4Msps,3路交替采样可到7.2Msps。
F1只有12个DMA通道,F4有16个DMA通道。F4的每个DMA通道有4*32位FIFO,F1没有FIFO。
F1的SPI时钟最高速度为 18MHz, F4可以到37.5MHz。
F1没有独立的32位定时器(32位需要级联实现),F4的TIM2和TIM5具有32位上下计数功能。
F1和F4都有2个I2S接口,但是F1的I2S只支持半双工(同一时刻要么放音,要么录音),而F4的I2S支持全双工,放音和录音可以同时进行。
串口数据设置为8位,加上一个起始位和一个停止位,应该是十位,为什么发送出来的是十一位
原因是每次发送都是采用以下语句来判断 while( USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET ); 这条语句检测到完成标志时 会产生 断开符 会在后面自行插多一个停止位进去,才造成有两个停止位的现象!!
在我发送一个数据包,在前面在数据都是使用while( USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET );来判断,数据位长度正确;
在最后一个字节是使用while( USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET );来判断的,其在停止位后面又插多了一个“1”
HC-05进入AT模式的两种方法及步骤演示
https://wenku.baidu.com/view/a87f5d06f46527d3250ce002.html
蓝牙小车代码
https://github.com/cstlrx/BlueTooth-and-detector-Car
很多标志位,只能由硬件置1,软件置1是无效的,但是软件置0有效,用来清除。
C++
引用形参和指针形参前面没有const限定符时,实参必须是非const的,而前面有const限定符时对实参也没有什么影响。
为什么会出现这种情况?
原因在于实参的传递方式不同,函数中的形参是普通形参的时,函数只是操纵的实参的副本,而无法去修改实参,实参会想,你形参反正改变不了我的值,那么你有没有const还有什么意义吗?引用形参和指针形参就下不同了,函数是对实参直接操纵,没有const的形参时实参的值是可以改变的,这种情况下怎能用函数来操纵const实参呢。
我一直这样记忆:“对于变量的约束,允许加强,当绝对不能削弱.....”
例如:实参是const,那么形参如果是非const意味着可以在函数体中改变形参的值,使约束削弱了所以不行。对于使用&,自然也是这个道理。同样的,指针里面的const也是这个样子的,如果让非const指针指向了const对象的地址,那么必然是无法通过编译的,因为如果这样做了,意味着可以通过这个指针改变本该是const的值了,显然是使约束削弱了
#include <iostream>
#include <string>
using namespace std;
void print_str( string & s)
{
cout<<s<<endl;
}
int main()
{
print_str("hello world");
return 0;
}
发现编译不通过,如果在第4行的string前加上一个const,就会通过编译。进一步研究我们会发现指针形参与引用形参会出现类似的情况。
双引号输入的字符串是const类型。如果要用指针或引用,必须加const。
关于整个流程:
- 使能时钟,初始化本身,使能本身。
- IO口不用使能本身。
- 延时需要初始化。delay_init(168);
- 中断需要初始化。
- https://wenku.baidu.com/view/6e3f5f3b83c4bb4cf7ecd19f.html###
这是串口通信比较好的透解,9600波特率包括了起始位和停止位,数据不会进入DR寄存器,而且停止位和下一个起始位之间有空闲位
嵌入式中的volatile
volatile 告诉编译器i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的可执行码会重新从i的地址读取数据放在k中。
而优化做法是,由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在k中。而不是重新从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问,不会出错。
http://blog.****.net/xy010902100449/article/details/48441785
定时器种类 |
位数 |
计数器模式 |
产生DMA请求 |
捕获/比较通道 |
互补输出 |
特殊应用场景 |
|
高级定时器 (TIM1,TIM8) |
16 |
向上,向下,向上/下 |
可以 |
4 |
有 |
带可编程死区的互补输出 |
|
通用定时器(TIM2,TIM5) |
32 |
向上,向下,向上/下 |
可以 |
4 |
无 |
通用。定时计数,PWM输出,输入捕获,输出比较 |
|
通用定时器(TIM3,TIM4) |
16 |
向上,向下,向上/下 |
可以 |
4 |
无 |
通用。定时计数,PWM输出,输入捕获,输出比较 |
|
通用定时器(TIM9~TIM14) |
16 |
向上 |
没有 |
2 |
无 |
通用。定时计数,PWM输出,输入捕获,输出比较 |
|
基本定时器 (TIM6,TIM7) |
16 |
向上,向下,向上/下 |
可以 |
0 |
无 |
主要应用于驱动DAC |
|
STM32F4与F1的时钟区别
Stm32F103只有八个16位的定时器
Stm32f407ZG有两个32位的定时器,12个16位的定时器
一个定时器的输出可以作为另一个定时器的输入
DR寄存器提供了内部总线和移位寄存器之间的并行接口,波特率包括了起始位和停止位,在移位寄存器中,起始位和停止位读取但不发送,只将数据位存储起来,用并行通信方式传给DR寄存器,软件读取时(res=receivedata();)也是DR用并行方式传给内部总线。
边沿:上升沿,下降沿
定时器通道,外部产生波形,边沿捕获
输出比较,通过对输出/捕获寄存器设置值,可以在定时器通道输出一个PWM波形
第31讲 通用定时器基本原理 -M4
边沿:上升沿,下降沿
定时器通道,外部产生波形,边沿捕获
输出比较,通过对输出/捕获寄存器设置值,可以在定时器通道输出一个PWM波形
极性,就是高低电平,是高电平有效还是低电平有效