第一节: 陌生的她和大叔
人近中年,不知不觉竟然成为孩子的父亲,不知不觉竟然成为别人的大叔,心中很是彷徨,我已不再年少。前些日子学习stm8,一口气工作近2个星期,当时精神饱满,心中很是得意,原来我也可以年轻。谁知放假去了次青岛和家人度假回来后竟然感冒了一个星期,哎,我还是老了。
写完stm8调试记后,就想践踏一下stm32,就像大叔和美女。。。因为只有美女才能让大叔觉得年轻,只有美女才能让大叔精力旺盛,stm32是我的美女吗?我不知道,我要接近她,我要驾驭她。
KEIL 的大名人尽皆知,51年代就大放异彩。说到这儿,不得不说一下那些为电子公益事业做出贡献的先行者们。甚是怀念那个年代,丁丁,老万,所长,午夜听风,龙啸九天等诸多大虾。他们推广keil,他们无私的奉献,就像现在的老key一样,知无不言,言无不尽。
我使用的环境: keil mdk 350
St 的 三合一板
板子虽小,还是可以做很多事情的,白菜老弟做的板子据说很强势,已经预定,现在先解下渴,玩玩只有一个STM32F103C8T6的小家碧玉。
Mdk350集成了st的st link,所以只要在OPTION FOR TARGET 的 DEBUG 和UTILITIES下选择st link debug就可以正确连接。库使用的是v2.01
我要让她跑起来,我需要做什么?
我要有一个时钟,目标是48mhz,这是为了以后调试usb
STM32的时钟和STM8的时钟基本上是一样的。她内部有个8mhz的振荡器,不过我不打算用它。三合一板外部焊接了一个8mhz的晶振我要用她做时钟源。
时钟初始化:
RCC_DeInit(); //恢复默认值这没什么用,不写他也不影响运行
RCC_HSEConfig(RCC_HSE_ON ); //启动外部时钟
while(!RCC_GetFlagStatus(RCC_FLAG_HSERDY));//等待外部时钟稳定
FLASH_SetLatency(FLASH_Latency_1); //48mhz运行时,flash要加一个等待周期
其实刚开始时我没有加这个延时,也没有什么不良的反应,不知道时间长了会不会有问题
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);//预缓冲使能
RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_6);//pll输出是外部时钟的6倍
RCC_PLLCmd(ENABLE); //使能pll
while(!RCC_GetFlagStatus(RCC_FLAG_PLLRDY));//等待pll稳定
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);//切换到PLL时钟
while(RCC_GetSYSCLKSource()!=0x8);//等待系统时钟稳定
RCC_PCLK1Config(RCC_HCLK_Div2);//低速时钟为24mhz
RCC_PCLK2Config(RCC_HCLK_Div1);//高速时钟为48mhz
经过上面的设置,时钟正是工作,我们可以通过这个函数RCC_GetClocksFreq();
来验证
RCC_ClocksTypeDef RCC_Clocks_T;
RCC_GetClocksFreq( &RCC_Clocks_T);
RCC_Clocks_T中反应了sys clk, HCLK PCLK1,PCLK2, ADC CLK的频率。
时钟有了,我们还要干点什么?板上有她唯一的外设,led小灯。我要让处于pb5的led亮。
//首先开启PB口的时钟,pb口在高速apb2上
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB,ENABLE );
下面要进行pb口的初始化
GPIO_InitTypeDef GPIOB_STR; //定义一个结构变量用于初始化
GPIOB_STR.GPIO_Pin = GPIO_Pin_5; //选择pb5
GPIOB_STR.GPIO_Speed = GPIO_Speed_10MHz; //最大10mhz输出
GPIOB_STR.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_Init( GPIOB,&GPIOB_STR); //配置pb5
Pb5已经配置好了,下面我要点亮led,pb5要输出1
GPIO_SetBits( GPIOB,GPIO_Pin_5);
相反熄灭她如下:
GPIO_ResetBits( GPIOB,GPIO_Pin_5);
这一节就到这,意法的库真是好东西,stm8调试的时候没有使用是因为实在不愿看那么多的代码。现在学习stm32,顺便把她的库看了看,觉得虽然庞大琐碎,但结构很优美,便用了起来。不过我怕用习惯了,把我自己用傻了,以后换别的cpu时,不会用了。
第二节 定时,中断,和意法的风骚
玩cpu吗当然等玩定时器,重要性在stm8一文中已有描述,这里不再多说。
我要使用tim2实现1s定时,这有些长不够实用,但是我只是玩玩。
第一步要配置时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_SPI2,ENABLE);
Tim2处于时钟树的apb1上。
下面是初始化代码
TIM2->PSC |=24000; //设置预分频,实现1ms
TIM2->ARR = 1000; //1s产生一次中断
TIM2->DIER |=0X1; //允许tim2更新中断
NVIC->ISER[0] |= (u32)(1<
TIM2->CR1 |=0X1;//启动tim2
说到这,不能不说意法的风骚,刚开始时翻遍手册也没看到nvic部分的说明,所以第一版本的tim2初始化没有nvic部分,以至不能进tim2的更新中断,后查阅阿莫的论坛才知有c_m3权威指南一物,实在让人无语。这是意法的风骚,这是新手的灾难。
每次新建工程时,keil会自动生成一个文件stm32f10x.s,在里面有中断向量表的描述。将相应的中断函数名实例化,就能实现中断入口。
我的tim2中断函数
void TIM2_IRQHandler(void)//这个函数名能在stm32f10x.s中找到
{
static u8 flag;
if( flag )
{
GPIO_SetBits( GPIOB,GPIO_Pin_5); //下面能实现上文说的led以0.5hz闪烁
flag = FALSE;
}
else
{
GPIO_ResetBits( GPIOB,GPIO_Pin_5);
flag = TRUE;
}
TIM2->SR &=0XFFFE; //清楚更新标志
}
上面没有用库函数,是因为我想自己的头脑里脉络更清楚,更复合我自己的风格。其实用库会简单
第三节 SPI和懒懒的我
调试stm8时没有调spi实在是因为没有接口,在加上我这人懒散最终没有调它,如果是美女,我就不会这么客气了吧。
最近身体欠佳,总感觉力不从心。又觉得时间匆匆,再不加把力气真要荒废此生,便生出无奈。
闲话少说,说说spi吧。三合一板只有一个cpu,但它却有两个spi,我用飞线将他们互联,便形成了一个完整的spi通讯接口。
Spi2处于时钟树的apb1,spi1处于时钟树的apb2,时钟部分已将apb1配置为24mhz
Apb2为48mhz
首先开启spi2和spi1时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2\
|RCC_APB1Periph_SPI2, \\这个是spi2的选项
ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB\
|RCC_APB2Periph_SPI1\ //这个是spi1的选项
|RCC_APB2Periph_GPIOA\
|RCC_APB2Periph_USART1,ENABLE
);
下面是spi的初始化
u32 x;
u8 y;
SPI_InitTypeDef SPI_X;
SPI_X.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //全双工
SPI_X.SPI_Mode = SPI_Mode_Slave;//式
SPI_X.SPI_DataSize = SPI_DataSize_8b;//
SPI_X.SPI_CPOL = SPI_CPOL_High;//时钟空闲是为高
SPI_X.SPI_CPHA = SPI_CPHA_2Edge;//
SPI_X.SPI_NSS = SPI_NSS_Soft;//软件控制
SPI_X.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_X.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI2,&SPI_X);
SPI2->CR2 |= (1<
NVIC->ISER[1] |= 0X10;//开spi2中断
SPI_X.SPI_Mode = SPI_Mode_Master;
SPI_Init(SPI1,&SPI_X); //spi1为主
SPI1->CR2 |= (1<
NVIC->ISER[1] |= 0X8;
SPI_Cmd(SPI2,ENABLE);
SPI_Cmd(SPI1,ENABLE);//使能spi1和spi2
SPI2->DR = 0Xaa;//发送数据
中断处理函数
void SPI1_IRQHandler( void )
{
u16 x;
if( SPI1->SR &0X1)
{
x = SPI1->DR;
}
if( SPI1->SR&0x2 )
{
SPI1->DR =++test_data1;
}
}
void SPI2_IRQHandler( void )
{
vu16 x;
if( SPI2->SR &0X1)
{
x = SPI2->DR;
if( sam_data < SIZE_BUF )
{
sam_data1[ sam_data++ ] =x;
}
else
{
sam_data = 0;
}
}
if( SPI2->SR&0x2 )
{
SPI2->DR =++test_data;
/* if(test_data1!=0)
{
test_data1 --;
}
else
{
test_data1 =10;
} */
}
}
外设使用的时候一定要先配置好io的使用模式。我就因为没有配置而吃了大亏。刚开始时收发怎么也不正常,后设置了io的方式才能工作。这大概是对新的事物还不熟悉。
Io的模式无非是,出的数据流设成输出,入的数据流设成输入,什么可说。
关于spi的代码,不是好的风格,其中库夹杂着自己的方法,如果在严格的风格上这不叫方法,叫发疯。
第四节:串口和新凤霞
最近听新凤霞的花为媒,让我有绕梁三日的感觉。喜欢的朋友可以听一下。老艺术家的东西越来越少了。时代在进步,我们在放弃。但放弃的都是优良的传统,如清廉,孝道,公正。
我手里有两个自己做的ch341转串口线缆,将小板的pa9(u1_TX,设置成推挽输出),和pa10(U1_RX,上拉输入)
和ch341相连,就完成了硬件配置。
我要实现的功能,当cpu收到计算机发来的0XAA时,发送8个0X55,在上电时cpu主动发送一次8个0X55.
首先配置时钟,
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB\
|RCC_APB2Periph_SPI1\ //这个是spi1的选项
|RCC_APB2Periph_GPIOA\
|RCC_APB2Periph_USART1,ENABLE //这个是串口项
);
下面是初始化:
USART_InitTypeDef uart_x;
NVIC_InitTypeDef nvic_x;
USART_Cmd(USART1,ENABLE); //使能串口
uart_x.USART_BaudRate = 19200;//19200, 8, n ,1
uart_x.USART_WordLength = USART_WordLength_8b;
uart_x.USART_StopBits = USART_StopBits_1;
uart_x.USART_Parity = USART_Parity_No;
uart_x.USART_Mode = USART_Mode_Rx |USART_Mode_Tx;//发送和接受
uart_x.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART1,&uart_x);
USART_ITConfig(USART1,USART_IT_TC,ENABLE);//使能发送完成中断
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//使能接受满中断
nvic_x.NVIC_IRQChannel = USART1_IRQChannel;//nvic的库开启方法
nvic_x.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic_x);
中断函数
void USART1_IRQHandler( void )
{
vu16 x;
vu16 y ;
y = USART1->SR;//读状态
if(y & 0X20)//如果是非空中断
{
x = USART1->DR&(u16)0xff;
// USART_SendData(USART1,0X55);
if( x == 0xaa )
{
lentch_x = 0;
USART1->CR1 |=(u16)0X8;//启动一次发送
}
}
if(y & 0X40)//发送完成中断
{
if(lentch_x < 8 )
{
USART1->DR = 0X55;
lentch_x++;
}
else
{
USART1->CR1 &=(u16)0XFFF7;; //清楚标志
}
}
}
阅读(3174) | 评论(0) | 转发(0) |