前面的例子研究了时钟,接下来就来了解一下引脚的情况<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
Main.c中,有关I/O口的配置代码如下:
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure IO connected to LD1, LD2, LD3 and LD4 leds *********************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
这几行代码是将GPIOD的第8,9,10和11引脚配置成输出,并且还可以设定输出引脚的速度(驱动能力?),这里设定为 50MHz,这应该是常用的,还有可以设置为2MHz的。那么如何将引脚设置成输入呢?查看电路原理图,GPIOD.0~GPIO.4是接一个摇杆的5个按钮的,因此,下面尝试着将它们设置成为输入端。
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOD, &GPIO_InitStructure);
第1行和第3行完全是照抄,第2行那个GPIO_Mode_IN_FLOATING是在stm<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />32f10x_gpio.h中找到的。
<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />
当然是因为这里还有GPIO_Mode_Out_PP,所以猜测应该是它了。至于还有其他那么多的符号就不管了。
定义完成,编译完全通过,那就接下来准备完成下面的代码了。
int main(void)
{
Init_All_Periph();
while(1)
{ if( GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_0)) //1
{ GPIO_ResetBits(GPIOD, GPIO_Pin_8);
}
else
{ /* Turn on LD1 */
GPIO_SetBits(GPIOD, GPIO_Pin_8);
/* Insert delay */
}
......
标号为1的行显然其作用是判断GPIOD.0引脚是0还是1。这个函数是在stm32f10x_gpio.c中找到的。
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
uint8_t bitstatus = 0x00;
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GET_GPIO_PIN(GPIO_Pin));
if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)Bit_RESET)
{
bitstatus = (uint8_t)Bit_SET;
}
else
{
bitstatus = (uint8_t)Bit_RESET;
}
return bitstatus;
}
虽然程序还有很多符号看不懂(没有去查),但凭感觉它应该是对某一个引脚的状态进行判断,因为这个函数的类型是uint8_t,估计stm32没有bit型函数(需要验证),所以就用了uint8_t型了),如果是读的端口的值,应该用uint16_t型。这一点在下面也可以得到部分的验证:
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx)
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx)
这些函数是读引脚及输出寄存器的数据的。
再次编译,也是顺利通过,依法炮制,将其他三个引脚输入控制LED的代码也写上,为保险起见,先用软件仿真,免得反复擦写FLASH(顺便说一句,目前还没有搞定将代码写入RAM及从RAM中执行,惭愧)
进入仿真后打开外围部件接口,单步执行,果然如同设想那样运作了,单击Pins 0后面的勾,再次运行,果然PIN8后面的勾没了。做到这里,就感觉到用keil的好处了,这块熟啊,几乎没有花时间在上面,一用就成了。
至此,按我的习惯,要翻开STM32F的数据手册,研究一下其IO端口了。下面是数据手册中的一段话:
-------------------------------------
每个GPI/O端口有两个32位配置寄存器(GPIOx_CRL,GPIOx_CRH),两个32位数据寄存器(GPIOx_IDR,GPIOx_ODR),一个32位置位/复位寄存器(GPIOx_BSRR),一个16位复位寄存器(GPIOx_BRR)和一个32位锁定寄存器(GPIOx_LCKR)。
根据数据手册中列出的每个I/O端口的特定硬件特征, GPIO端口的每个位可以由软件分别配置成多种模式。
─ 输入浮空
─ 输入上拉
─ 输入下拉
─ 模拟输入
─ 开漏输出
─ 推挽式输出
─ 推挽式复用功能
─ 开漏复用功能
----------------------------------------------------
当然,数据手册上关于IO端口的描述是很多很多的,我也只是大概地了解了一下,真正要设计产品时,肯定还要细看。但至少,知道了IO端口复位后处于浮空状态,也就是其电平状态由外围电路决定,这很重要,如果设计工业品的话,这是必须要确定的;知道了IO引脚可以兼容5V电源;知道了在什么地方可以找到这些引脚在库中的定义而不必看着数据手册去控制那些位;也知道了这些引脚的一些基本操作函数(连猜带蒙带测试应该可以搞定大部分功能),那么我心里基本就有底啦。
最后用一段电子荧火虫(也就是呼吸灯)的简单程序作为结束。
int main(void)
{ uint8_t Count;
uint32_t DelayTim="0x1000"; //基数
uint32_t ChangTim="0x2000"; //每次变化的量
Init_All_Periph();
while(1)
{
for(Count=0;Count<16;Count++) //渐亮
{
GPIO_SetBits(GPIOD, GPIO_Pin_8); //点亮灯
Delay(DelayTim+Count*ChangTim);
GPIO_ResetBits(GPIOD, GPIO_Pin_8); //熄灭灯
Delay(DelayTim+(16-Count)*ChangTim);
}
for(Count=16;Count>0;Count--) //渐暗
{
GPIO_SetBits(GPIOD, GPIO_Pin_8); //点亮灯
Delay(DelayTim+Count*ChangTim);
GPIO_ResetBits(GPIOD, GPIO_Pin_8); //熄灭灯
Delay(DelayTim+(16-Count)*ChangTim);
}
}
}
这段程序的相关知识,这里就不再多说了,有兴趣可以看我的另一篇文章:
http://blog.ednchina.com/czlyzhj/269243/message.aspx
http://blog.ednchina.com/czlyzhj/283594/message.aspx
文章评论(0条评论)
登录后参与讨论